오늘의 문제: 25325번
학생 명단과 학생별 추천 리스트가 주어졌을 때, 각 학생의 득표수를 계산하고 득표수 내림차순, 이름 오름차순으로 정렬하여 출력하는 문제이다.
문제 요구사항:
1. 초기 학생 명단 주어짐
2. 각 줄마다 추천 학생 리스트 주어짐
3. 각 학생이 받은 총 추천 수 계산 (단, 초기 명단에 있는 학생만 유효)
4. 결과 정렬: 득표수 많은 순 -> 이름 사전 순
5. 결과 출력: 이름 득표수
딕셔너리를 사용해 학생 이름과 득표수를 저장하고, 마지막에 sorted
를 이용해 정렬하는 방향으로 접근했다.
// 초기 제출했던 코드
let volume = Int(readLine()!)!
var container = [String: Int]()
var students = readLine()!.split(separator: " ")
for student in students {
container[String(student)] = 0
}
for _ in 0..<volume {
let info = readLine()!.split(separator: " ")
// 🚨 문제점: 추천 명단(info)에 있는 모든 이름에 대해 점수를 더함
// 초기 학생 명단(students)에 없는 학생도 점수를 받을 수 있음
for value in info {
container[String(value), default: 0] += 1
}
}
let result = container.sorted(by: {
if $0.value == $1.value {
return $0.key < $1.key // 점수 같으면 이름 오름차순
} else {
return $0.value > $1.value // 점수 내림차순
}
})
for (name, record) in result {
print("\(name) \(record)")
}
초기 코드의 핵심적인 문제점은 득표수를 계산하는 로직에 있었다.
for value in info
루프는 추천 명단(info
)에 있는 모든 이름을 순회하며 container
딕셔너리의 값을 증가시킨다. 하지만 문제 조건은 초기 학생 명단(students
)에 있는 학생들만 점수를 얻어야 한다.
만약 추천 명단에만 있고 초기 학생 명단에 없는 학생 이름이 등장하면, 이 학생에게도 불필요하게 점수가 부여되는 오류가 발생한다.
개선 방향: 득표수를 증가시키기 전에, 해당 학생 이름(value
)이 초기 학생 명단 딕셔너리(container
)에 키로 존재하는지 확인하는 절차를 추가한다.
문제점을 해결하기 위해 if container[name] != nil
조건을 추가하여, 초기 명단에 있는 학생인 경우에만 점수를 증가시키도록 수정했다.
let n = Int(readLine()!)!
let studentNames = readLine()!.split(separator: " ")
var scores = studentNames.reduce(into: [:] { $0[String($1)] = 0 })
for _ in 0..<n {
let recommended = readLine()!.split(separator: " ")
for nameSubstring in recommended {
let name = String(nameSubstring) // Substring -> String 변환
// ✨ 개선된 부분: 초기 명단에 있는 학생인지 확인
if scores[name] != nil {
scores[name, default: 0] += 1 // 존재하면 점수 증가
}
}
}
// 결과 정렬 (정렬 로직은 초기 코드와 동일)
let sortedScores = scores.sorted { (first, second) -> Bool in
if first.value == second.value {
return first.key < second.key // 점수 같으면 이름 오름차순
} else {
return first.value > second.value // 점수 내림차순
}
}
// 결과 출력
for (name, score) in sortedScores {
print("\(name) \(score)")
}
split
으로 얻어지는 Substring
타입은 필요시 String
으로 명시적 변환이 필요하다는 점을 다시 상기했다.reduce
를 활용하는 방법을 알게 되었으나, 가독성을 고려하여 for
루프를 사용할 수도 있다.sorted(by:)
클로저를 이용해 복합적인 정렬 기준(값 내림차순, 키 오름차순)을 명확하게 구현할 수 있다.