

오늘도 겨우겨우 Day6를 끝냄.
기록은 또... ai에 맡겼다. 코드를 풀면서 적든가 해야지... 끝나고 쓰려니까 기억도 안나고? 집중도 안된다 ㄷㄷ
최근에 잠을 많이 못 자서 그런 것 같기도 하고...

각 query는
[s, e, k]형태이다.
s부터e까지의 인덱스를 확인한다.- 해당 범위에서
arr[i]가k보다 큰 값만 찾는다.- 조건을 만족하는 값이 여러 개라면 그중 가장 작은 값을 선택한다.
- 조건을 만족하는 값이 없다면
-1을 저장한다.- 모든 query에 대해 위 과정을 반복하여 결과 배열을 반환한다.
def solution(arr, queries):
# query = [s, e, k] 꼴
# 각 쿼리마다 s <= i <= e 인 i 중에서
# k < arr[i]일 때, 가장 작은 arr[i]
for query in queries:
s = query[0]
e = query[1]
k = query[2]
i = (s <= i) and (i <= e)
if k < arr[i]:
...
처음에는 s <= i <= e라는 지문의 조건을 그대로 코드의 조건식으로 만들려고 했다.
하지만 여기서 i는 True/False를 저장하는 변수가 아니라, s부터 e까지 실제 인덱스를 하나씩 움직여야 하는 값이었다.
따라서
i = (s <= i) and (i <= e)
가 아니라,
for i in range(s, e + 1):
처럼 범위를 순회해야 했다.
이후 조건을 만족하는 값을 찾으면서 처음에는 다음과 같이 작성했다.
if k < arr[i]:
answer += min(arr[i])
하지만 arr[i]는 이미 정수 하나이기 때문에 min()을 사용할 수 없었다.
min()을 사용하려면 먼저 조건을 만족하는 여러 후보를 리스트에 저장한 뒤, 그 리스트에서 최솟값을 구해야 했다.
그래서 후보 리스트를 추가했다.
i_list = []
for i in range(s, e + 1):
if k < arr[i]:
i_list.append(arr[i])
여기서 또 하나 헷갈렸던 부분은 min()을 실행하는 위치였다.
처음에는 다음처럼 작성했다.
for i in range(s, e + 1):
if k < arr[i]:
i_list.append(arr[i])
if i_list != []:
answer.append(min(i_list))
이렇게 작성하면 후보를 하나 발견할 때마다 그 순간의 최솟값이 answer에 계속 들어간다.
이 문제는 query 하나당 결과 하나만 필요하기 때문에, 먼저 범위를 끝까지 돌며 후보를 모두 모은 후 min()을 실행해야 했다.
def solution(arr, queries):
answer = []
for query in queries:
s = query[0]
e = query[1]
k = query[2]
i_list = []
for i in range(s, e + 1):
if k < arr[i]:
i_list.append(arr[i])
if i_list != []:
answer.append(min(i_list))
else:
answer.append(-1)
return answer
이번 문제에서 가장 헷갈렸던 부분은 반복하면서 하는 일과 반복이 끝난 뒤 하는 일을 구분하는 것이었다.
크게 보면
s ~ e범위의 인덱스를 순회한다.arr[i] > k를 만족하는 값을 후보 리스트에 저장한다.- 모든 인덱스를 확인한 뒤 후보가 존재하는지 확인한다.
- 후보가 있으면
min(), 없으면-1을 저장한다.
즉 구조는 다음과 같다.
query 하나 선택
↓
s, e, k 분리
↓
s ~ e 반복
↓
arr[i] > k ?
↓
조건 만족 값 후보 리스트에 저장
↓
반복 종료
↓
후보 있음 → min()
후보 없음 → -1
↓
answer에 저장
또 하나 배운 점은 문제에서
s <= i <= e
라고 주어졌다고 해서 항상 그대로 if 조건으로 옮기는 것이 아니라는 점이다.
이번 경우에는 이 문장이 "i가 이 범위를 움직인다"는 뜻이므로
for i in range(s, e + 1):
로 표현하는 것이 적절했다.
그리고
answer
와
i_list
의 역할도 구분해야 했다.
i_list
→ 현재 query 하나를 풀기 위한 임시 후보 저장소
answer
→ 각 query의 최종 결과를 저장하는 리스트
따라서 i_list = []는 새로운 query를 처리할 때마다 초기화되어야 한다.
후보를 전부 리스트에 저장하지 않고, 현재까지 찾은 최솟값 하나만 기억하는 방법도 있다.
def solution(arr, queries):
answer = []
for s, e, k in queries:
result = -1
for i in range(s, e + 1):
if arr[i] > k:
if result == -1 or arr[i] < result:
result = arr[i]
answer.append(result)
return answer
이 방식은 후보 리스트를 만들지 않고
조건을 만족하는 값 발견
→ 현재 result보다 작은지 확인
→ 더 작다면 result 교체
하는 방식이다.
현재는 후보를 리스트에 모은 뒤 min()을 사용하는 방식이 더 직관적으로 이해된다.
이번 문제는 조건 자체보다 문제의 문장을 반복문의 구조로 바꾸는 과정에서 많이 막혔다.
특히 s <= i <= e를 보고 처음에는 조건식부터 만들려고 했는데, 실제로 필요한 것은 s부터 e까지 인덱스를 하나씩 확인하는 반복문이었다.
또 조건을 만족하는 순간 바로 답을 구하려고 했지만, "가장 작은 값"은 모든 후보를 확인한 뒤 결정해야 한다는 점도 놓쳤다.
앞으로 문제를 볼 때는 바로 코드를 쓰기보다,
무엇을 반복하는가?
반복하면서 무엇을 모으는가?
반복이 끝난 뒤 무엇을 결정하는가?
를 먼저 나눠보는 연습이 필요할 것 같다.
오늘 리스트의 뒤에서 첫 번째, 두 번째 값을 가져와야 하는 상황에서 list[-1], list[-2] 대신 list[::-1], list[::-2]를 사용했다.
arr = [10, 20, 30, 40, 50]
arr[-1] # 50
arr[-2] # 40
arr[::-1] # [50, 40, 30, 20, 10]
arr[::-2] # [50, 30, 10]
핵심은 [] 안에 콜론(:)이 있느냐로 구분할 수 있다.
arr[-1] → 인덱싱: 뒤에서 1번째 값 하나arr[-2] → 인덱싱: 뒤에서 2번째 값 하나arr[::-1] → 슬라이싱: 뒤에서부터 1칸씩 → 전체 역순arr[::-2] → 슬라이싱: 뒤에서부터 2칸씩 → 역순으로 건너뛰기회고:
-1을 무조건 "역순"이라고 생각해서 헷갈렸다. 앞으로는 값 하나를 찾는지 → 인덱싱, 여러 값을 일정한 간격으로 자르는지 → 슬라이싱을 먼저 구분해야겠다. 특히 :이 들어가면 [시작:끝:간격] 형태의 슬라이싱이라는 점을 기억하자.
