1 문제 1: 문자열 내림차순 정렬
| 항목 | 내용 |
|---|---|
| 출처 | Programmers |
| 난이도 | Level 1 |
| 유형 | String |
| 풀이 시간 | 5분 |
1.1 문제 설명
문자열 s가 주어질 때, 모든 문자를 내림차순으로 정렬한 새 문자열을 반환한다.
입출력 예시
| s | return |
|---|---|
"Zbcdefg" |
"gfedcbZ" |
제한사항
1 <= len(s) <= 10,000- 문자열은 한글자 이상의 모든 문자를 포함 가능
1.2 핵심 알고리즘/자료구조
핵심: sorted()와 reverse 옵션
sorted() 함수는 문자열을 정렬하여 리스트를 반환한다. - sorted(s) — 오름차순 정렬 (기본) - sorted(s, reverse=True) — 내림차순 정렬
정렬된 리스트를 문자열로 변환하려면 ''.join() 을 사용한다.
- 시간 복잡도: O(n log n) — 정렬
- 공간 복잡도: O(n) — 정렬 결과 저장
1.3 풀이 접근법
- 문자열을 문자 단위로 정렬 —
sorted(s)로 리스트 변환 - 내림차순으로 정렬 —
reverse=True옵션 추가 - 리스트를 문자열로 변환 —
''.join()사용
1.4 코드 풀이
def solution(s: str) -> str:
"""
문자열을 내림차순으로 정렬하여 반환한다.
Unicode 값 기준 내림차순: 대문자 > 소문자
"""
return ''.join(sorted(s, reverse=True))복잡도 분석
- 시간 복잡도: O(n log n) —
sorted()정렬 - 공간 복잡도: O(n) — 정렬된 리스트 저장
1.5 테스트 케이스 트레이싱
solution("Zbcdefg")
# sorted("Zbcdefg", reverse=True)
# → ['g', 'f', 'e', 'd', 'c', 'b', 'Z']
# (Unicode: 소문자 g~b > 대문자 Z)
# ''.join(...) → "gfedcbZ" ✓
solution("Za")
# sorted("Za", reverse=True) → ['a', 'Z']
# 결과 → "aZ" ✓
solution("abc")
# sorted("abc", reverse=True) → ['c', 'b', 'a']
# 결과 → "cba" ✓1.6 다른 풀이
# 접근 1: list 변환 후 sort() 사용
def solution_v2(s: str) -> str:
chars = list(s)
chars.sort(reverse=True)
return ''.join(chars)
# 접근 2: 슬라이싱을 이용한 문자 순회 (비효율)
def solution_v3(s: str) -> str:
result = ""
sorted_chars = sorted(s, reverse=True)
for char in sorted_chars:
result += char # O(n²) — 문자열 concatenation
return result| 풀이 | 장점 | 단점 |
|---|---|---|
''.join(sorted(...)) |
간결, Pythonic | |
list.sort() + join |
명시적 | 한 줄 더 필요 |
| 문자열 concatenation | 직관적 | O(n²) 느림 |
1.7 핵심 패턴
이 문제에서 배운 것
sorted(s, reverse=True)— 내림차순 정렬''.join(list)— 리스트를 문자열로 합치기 (String 문제의 기본)- Unicode 정렬 순서 — ASCII: 대문자(65~90) < 소문자(97~122)
- Pythonic 표현 — 여러 줄 루프보다 한 줄 함수 조합이 깔끔
면접 방어 포인트
- 왜
sorted()인가? — 단순성. 커스텀 정렬이 필요 없으면 내장 함수 활용 - 시간복잡도? — O(n log n). 선형 정렬(Counting Sort)을 쓸 수도 있지만 필요 없음
sorted()vslist.sort()? — 새 리스트 반환 vs 제자리 정렬. 이 문제는 원본 유지 필요 없으므로 둘 다 가능''.join()필수인 이유? — 반환 타입이 str이어야 하기 때문
2 문제 2: 가장 많이 나타나는 문자
| 항목 | 내용 |
|---|---|
| 출처 | Programmers |
| 난이도 | Level 1 |
| 유형 | String |
| 풀이 시간 | 10분 |
2.1 문제 설명
문자열 s가 주어질 때, 가장 많이 나타나는 문자를 반환한다. 만약 여러 문자가 같은 빈도로 가장 많이 나타나면, 사전순으로 앞선 문자를 반환한다.
입출력 예시
| s | return |
|---|---|
"abracadabra" |
"a" |
"hello" |
"l" |
"aabbcc" |
"a" |
제한사항
1 <= len(s) <= 10,000- 문자열은 소문자 영문자만 포함
2.2 핵심 알고리즘/자료구조
핵심: Counter와 동일 빈도 처리
Counter(s) 는 각 문자의 빈도를 dict로 반환한다.
주의: Counter.most_common(1) 은 최대 빈도인 첫 번째 항목만 반환하므로, 동일 빈도인 경우 어느 것을 반환할지 보장하지 않는다. 사전순 처리가 필요하다.
- 시간 복잡도: O(n) — Counter 생성 + 최대값 계산
- 공간 복잡도: O(k) — k는 고유 문자 수 (≤ 26)
2.3 풀이 접근법
- 문자 빈도 계산 —
Counter(s)로 각 문자의 등장 횟수 파악 - 최대 빈도 찾기 —
max(count.values()) - 최대 빈도인 모든 문자 필터링 — 조건부 리스트컴프리헨션
- 사전순 최소 선택 —
min()함수
2.4 코드 풀이
from collections import Counter
def solution(s: str) -> str:
"""
가장 많이 나타나는 문자를 반환.
동일 빈도면 사전순 첫 번째.
"""
count = Counter(s)
max_freq = max(count.values())
# 최대 빈도인 모든 문자 중 사전순 최소
return min(c for c, f in count.items() if f == max_freq)복잡도 분석
- 시간 복잡도: O(n) — Counter 생성, 최대값 찾기, 최소값 찾기 모두 O(n) 또는 O(k)
- 공간 복잡도: O(k) — Counter 저장 (k = 고유 문자 수)
2.5 테스트 케이스 트레이싱
solution("abracadabra")
# count = Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
# max_freq = 5
# 최대 빈도인 문자: ['a']
# min(['a']) = "a" ✓
solution("aabbcc")
# count = Counter({'a': 2, 'b': 2, 'c': 2})
# max_freq = 2
# 최대 빈도인 문자: ['a', 'b', 'c']
# min(['a', 'b', 'c']) = "a" ✓
solution("hello")
# count = Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})
# max_freq = 2
# 최대 빈도인 문자: ['l']
# min(['l']) = "l" ✓2.6 다른 풀이
# 접근 1: most_common() 직접 사용 (동일 빈도 미처리 — 위험)
def solution_wrong(s: str) -> str:
count = Counter(s)
return count.most_common(1)[0][0] # 어느 것을 반환할지 보장 안 함
# 접근 2: sorted 조합 (명시적)
def solution_v2(s: str) -> str:
count = Counter(s)
# (빈도, 문자)로 정렬: 빈도 내림차순, 문자 오름차순
sorted_items = sorted(count.items(), key=lambda x: (-x[1], x[0]))
return sorted_items[0][0]| 풀이 | 장점 | 단점 |
|---|---|---|
min(c for ... if f == max_freq) |
직관적, 안전 | 코드 3줄 |
sorted(..., key=...) 조합 |
한 줄 가능 | 정렬 비용 O(k log k) |
most_common(1) |
간단 | 동일 빈도 미처리 |
2.7 핵심 패턴
이 문제에서 배운 것
Counter(s)— 빈도 카운팅 자동화max(dict.values())— dict의 값 최댓값 찾기min()with 조건 — 조건을 만족하는 최솟값 찾기 (사전순)- 동일 값 처리 —
most_common(1)은 보장 안 함 → 필터 + min/max 조합 필수
면접 방어 포인트
- 왜
Counter인가? — 빈도 카운팅이 명확하고 간단 most_common(1)왜 안 쓰나? — 동일 빈도일 때 순서 미보장 → 직접 필터링이 안전- 시간복잡도? — O(n). 소문자 26개로 제한되면 O(1)로도 봐줄 수 있음
- 공간복잡도? — O(k). 소문자만이면 O(26) = O(1)
3 관련 문제
- 포켓몬 (Hash Level 1) —
set, 카운팅 - Python 내장 함수·자료구조 (Level 1~2) —
sorted(),join()