소문자로만 구성된 문자열 리스트 votes가 있다고 가정해 보겠습니다. 각 항목은 선호도가 가장 높은 순서부터 가장 낮은 순서까지 후보자에게 표현된 투표를 의미합니다.
후보자의 순위는 다음 규칙에 따라 결정됩니다.
- 먼저 1순위(최고 선호) 득표 수가 많은 순서대로 정렬됩니다.
- 1순위 득표 수가 같다면, 2순위 득표 수를 비교하고, 그래도 같으면 그다음 선호도 순위의 득표 수를 차례대로 비교합니다.
- 모든 순위에서 득표 수가 동일하다면, 알파벳 순서로 최종 순위를 매깁니다.
이 규칙을 적용하여 전체 팀(후보)의 최종 순위를 높은 순위부터 낮은 순위까지 구하는 것이 목표입니다.
예시
입력이 votes = ["zyx", "zxy", "xyz"]라면 출력은 "zxy"가 됩니다. 그 이유는 다음과 같습니다.
- z: 1순위 득표가 2표로 가장 많으므로 1위입니다.
- x: 1순위 득표가 1표로 두 번째이므로 2위입니다.
- y: 1순위 득표가 없으므로 3위입니다.
풀이 접근 방법
이 문제는 다음 단계로 해결할 수 있습니다.
count:= 투표 문자열의 길이 (선호도 순위의 개수)cand:= 비어 있는 딕셔너리(map). 각 키(후보)에는 크기가count인 리스트가 연결되며, 초기값은 모두 0으로 채워집니다.votes의 각 문자열v에 대해:- 각 인덱스
i와 문자c에 대해cand[c][i]값을 1씩 증가시킵니다. 즉, 후보c가 i+1번째 선호 순위에서 받은 표의 개수를 누적합니다.
- 각 인덱스
cand의 항목들을 값 기준 내림차순으로 정렬합니다. 값이 같을 경우 알파벳 순서로 정렬합니다.- 정렬된 요소들을 이어 붙여 하나의 문자열로 만들어 반환합니다.
구현 코드
from collections import defaultdict
class Solution:
def solve(self, votes):
count = len(votes[0])
cand = defaultdict(lambda: [0] * count)
for v in votes:
for i, c in enumerate(v):
cand[c][i] += 1
return "".join(sorted(cand.keys(), key=lambda x: (cand[x], -ord(x)), reverse=True))
ob = Solution()
votes = ["zyx", "zxy", "xyz"]
print(ob.solve(votes))입력
["zyx", "zxy", "xyz"]
출력
zxy
코드 설명
핵심은 마지막 줄의 정렬 로직입니다. 정렬 키인 (cand[x], -ord(x))는 두 부분으로 구성됩니다.
cand[x]: 각 선호 순위별 득표 수를 담은 리스트입니다. 파이썬은 리스트를 사전식(lexicographic)으로 비교하므로, 자동으로 1순위 → 2순위 → 3순위 순서로 득표 수를 비교하게 됩니다.-ord(x): 득표 수가 완전히 같을 때 사용되는 타이브레이커입니다.reverse=True와 함께 사용되므로-ord()값이 더 큰, 즉 알파벳 순서상 앞선 문자가 먼저 배치됩니다.
이처럼 defaultdict와 파이썬의 다중 조건 정렬을 활용하면 복잡한 순위 규칙도 간결한 코드로 처리할 수 있습니다.