비내림차순으로 정렬된 수열이 주어질 때, 다음 조건을 만족하는 부분 수열을 찾으려고 합니다.
수열을 나타내는 정수 배열 sequence와 부분 수열의 합을 나타내는 정수 k가 매개변수로 주어질 때, 위 조건을 만족하는 부분 수열의 시작 인덱스와 마지막 인덱스를 배열에 담아 return 하는 solution 함수를 완성해주세요. 이때 수열의 인덱스는 0부터 시작합니다.
제한사항
sequence의 길이 ≤ 1,000,000sequence의 원소 ≤ 1,000sequence는 비내림차순으로 정렬되어 있습니다.k ≤ 1,000,000,000k는 항상 sequence의 부분 수열로 만들 수 있는 값입니다.
내 풀이
문제를 풀 당시에는 투 포인터 라는 개념이 생각나지 않았다.
그래서 그저 문제에서 요구한 대로 반복문을 통해 숫자를 하나씩 큐에 넣어주고, 부분합을 구했다.
for문 구조는 다음과 같다.
i번째 수 이전까지의 부분합(sum)이 k보다 커지면, 큐에서 왼쪽부터 하나씩 빼면서 부분합이 k보다 작거나 같을때 까지 반복한다. 이때 start는 1씩 증가시킨다.
그리고 while문이 끝난 후, 만약 부분합이 k와 같아지면, start와end를 기록한다. 이때 그 간격이 짧은 것을 찾아야 하므로 end - start < result 조건을 통해 짧은 간격일때만 기록한다.
"길이가 짧은 수열이 여러 개인 경우 앞쪽(시작 인덱스가 작은)에 나오는 수열을 찾습니다." 라는 조건 때문이다.i번째 수를 큐와 부분합에 추가해주고, end를 i로 갱신.
from collections import deque
def solution(sequence, k):
answer = []
sequence += [0]
q = deque()
sum = 0
start, end = 0, 0
result = len(sequence)
for i in range(len(sequence)):
while sum > k:
temp = q.popleft()
sum -= temp
start += 1
if sum == k and end - start < result:
answer = [start, end]
result = end - start
q.append(sequence[i])
sum += sequence[i]
end = i
return answer
투 포인터 정석 풀이
우선 부분합을 기록할 max_sum과 끝 포인터인 end를 선언해준다.
이후 for문을 돌리는데, 이때 시작 포인터인 start를 사용.
로직은 간단하다. 부분합이 k보다 크거나 같을때 까지 end를 1씩 증가시키며 더해준다.
이후 부분합이 k와 같은지 비교하고, 만약 같다면 기록을 해준다.
그리고 마지막으로 현재 부분합은 k보다 크거나 같으므로, start 위치의 값을 빼주고 다음 반복문을 진행한다.
즉, 정리하면 다음과 같다.
def solution(sequence, k):
n = len(sequence)
max_sum = 0
end = 0
interval = n
for start in range(n):
while max_sum < k and end < n:
max_sum += sequence[end]
end += 1
if max_sum == k and end-1-start < interval:
res = [start, end-1]
interval = end-1-start
max_sum -= sequence[start]
return res
요거 따라해보면서 궁금했던게
저는 interval = n + 1
로 풀었는데 저는 길이가 start부터 end-1까지라 end - 1 - start + 1 로 end-start라 생각해서 풀었는데요,
동일하게 정답으로 처리되는데 혹시 end-start -1로 푸신 이유가 무엇인지 궁금해서 여쭤봅니다!