Phase 1 전 영역 종합 복습 테스트. 리스트, 딕셔너리, 문자열, 집합, 내장함수, 튜플, 함수, 예외 처리까지 골고루 10문제를 풀어 Phase 2 전환 여부를 판단한다.
n×n 행렬의 주대각선 합을 구하는 문제. 대각선 원소는 행과 열 인덱스가 같으므로 matrix[i][i]로 접근한다.
total += matrix[i][i] # (0,0), (1,1), (2,2) → 주대각선
✅ 1차 정답
문자열에서 가장 많이 등장한 문자를 반환하는 문제.
1차 시도: sorted(count)[0] → 오답. sorted(dict)는 키를 알파벳순으로 정렬할 뿐, 등장 횟수와 무관하다.
정답: max(count, key=count.get)
max(count, key=count.get) # 값(등장 횟수)이 가장 큰 키를 반환
min(count, key=count.get) # 값이 가장 작은 키를 반환
수업 중 질문: "key=count.get할 때 get()에 키 값이 없어도 되나?"
→count.get은 호출(count.get('a'))이 아니라 함수 자체를 넘기는 것.max가 내부적으로 각 키를 넣어서 호출해주기 때문에 우리가 키를 지정할 필요가 없다. Java의 메서드 레퍼런스(count::get)와 같은 개념.
각 단어의 첫 글자를 대문자로 바꾸는 문제. capitalize() 메서드를 써봤더니 동작했다.
result.append(w.capitalize()) # 첫 글자 대문자 + 나머지 소문자
return " ".join(result)
| 방법 | 동작 |
|---|---|
w.capitalize() | 첫 글자 대문자 + 나머지 소문자 |
w[0].upper() + w[1:] | 첫 글자만 대문자 + 나머지 그대로 |
w.title() | 각 단어 첫 글자 대문자 (문자열 전체에 적용) |
capitalize()를 몰라도 w[0].upper() + w[1:]로 대체 가능.
✅ 1차 정답
두 리스트의 공통 원소를 원래 순서 유지하며 반환하는 문제.
1차 시도: 리스트 컴프리헨션으로 교집합 리스트를 만들어 비교 → 동작은 하지만 set을 활용하는 문제 의도와 다름.
정답: list2를 set으로 변환 후 in 검사.
common = set(list2)
return [x for x in list1 if x in common]
set을 쓰면 in 검색이 O(1)으로 빠르다.
점수 내림차순 + 이름 오름차순으로 정렬하는 문제. 정렬 기준이 여러 개일 때 튜플로 묶어서 반환한다는 걸 새로 배웠다.
sorted(students, key=lambda x: (-x[1], x[0]))
-를 붙이면 크기 관계가 뒤집혀서 내림차순이 된다. 단, 숫자에만 가능.
수업 중 질문: "조건 2개 이상이라 튜플로 줘야 될 때 reverse=True는 어디에?"
→reverse=True는sorted()의 매개변수로 넣지만 전체 기준이 다 뒤집히므로, 방향이 섞여 있으면 사용 불가.
| 상황 | 방법 |
|---|---|
| 기준이 같은 방향 | key=(기준1, 기준2) + reverse=True/False |
| 숫자가 다른 방향 | - 트릭: (-x[1], x[0]) |
| 문자열이 다른 방향 | sorted 두 번 (덜 중요한 기준 먼저) |
sorted 두 번 쓰는 방법은 Python의 안정 정렬(stable sort) 을 이용. 같은 값이면 이전 순서를 유지하므로, 덜 중요한 기준을 먼저 정렬하고 더 중요한 기준을 나중에 정렬하면 된다.
바깥 함수의 변수를 내부 함수에서 수정하려면 nonlocal 선언이 필요하다.
def increment(n):
nonlocal count # 함수 시작 부분에 선언 (관례)
for i in range(n):
count += 1
✅ 1차 정답
변환 실패한 값을 "건너뛰는" 함수인데, except에서 실패한 값을 리스트에 추가하고 있었다. result.append(s) → continue로 수정.
수업 중 질문: "int(4.5)는 4가 되는데 int('4.5')는 ValueError가 뜨는 이유?"
→int()는 입력 타입에 따라 동작이 다르다. float → 소수점 버림, 문자열 → 정수 형태만 파싱 가능."4.5"를 정수로 바꾸려면int(float("4.5"))로 두 단계 거쳐야 한다.
✅ 1차 정답
def get_winner(votes):
result = {}
for vote in votes:
result[vote] = result.get(vote, 0) + 1
return max(result, key=result.get)
문제 2에서 배운 max(dict, key=dict.get) 패턴을 바로 활용했다. 개선점으로 if/else 분기 없이 get(vote, 0)만으로 충분하고, sorted()[0] 대신 max()가 더 효율적이라는 피드백을 받았다. sorted()는 전체를 정렬(O(n log n))하지만 max()는 한 번 순회(O(n))만 하면 되기 때문.
✅ 1차 정답
사고 과정: palindrome과 헷갈림 → set 교집합은 중복 제거돼서 안됨 → 값을 빼가면서 체크? → 힌트 후 sorted 비교로 해결.
def is_anagram(s1, s2):
return sorted(s1) == sorted(s2)
정렬하면 글자 구성이 같은지 바로 비교 가능. Counter(s1) == Counter(s2)도 유효.
수업 중 질문: "Counter가 뭔지 찾아봤는데 딕셔너리끼리도 == 비교가 가능한가?"
→ 가능. 키와 값이 모두 같으면 True, 순서와 무관. Java의map1.equals(map2)와 동일.
가장 난이도가 높았던 문제. 힌트를 받아 방향 배열 + 방향 전환 구조로 직접 구현했다.
def make_spiral(n):
grid = [[0] * n for _ in range(n)]
dr = [0, 1, 0, -1] # 오른쪽 → 아래 → 왼쪽 → 위
dc = [1, 0, -1, 0]
r, c = 0, 0
d = 0
for num in range(1, n * n + 1):
grid[r][c] = num
nr, nc = r + dr[d], c + dc[d]
if nr < 0 or nr >= n or nc < 0 or nc >= n or grid[nr][nc] != 0:
d = (d + 1) % 4
nr, nc = r + dr[d], c + dc[d]
r, c = nr, nc
return grid
디버깅 과정: n=3은 통과했는데 n=4에서 실패. 원인은 if d == n으로 방향 리셋을 했기 때문. n=3일 때 d == 3이 우연히 맞았지만, n=4일 때 d == 4는 절대 발생하지 않음. (d + 1) % 4로 수정하여 해결.
자발적 추가 연습: 반시계 방향 + 역순(n×n → 1)도 직접 구현. 방향 배열만 바꾸고 range를 역순으로 변경하여 성공.