비내림차순으로 정렬된 수열이 주어질 때, 다음 조건을 만족하는 부분 수열을 찾으려고 합니다.
수열을 나타내는 정수 배열 sequence와 부분 수열의 합을 나타내는 정수 k가 매개변수로 주어질 때, 위 조건을 만족하는 부분 수열의 시작 인덱스와 마지막 인덱스를 배열에 담아 return 하는 solution 함수를 완성해주세요. 이때 수열의 인덱스는 0부터 시작합니다.
투 포인터 알고리즘
을 이용하였다.candidate
로 선언한다.sequence[s]
로 초기화한다.sum > k
=> sum에서 sequence[s]
를 빼고, s를 증가시킨다.sum < k
=> e를 증가시키고, sum에 sequence[e]
를 더한다.sum == k
=> candidate
배열에 현재 [s, e]
배열을 추가하고, s와 e를 각각 1씩 증가시킨다.e < sequence.length
일 동안 반복한다.sol.
누적 합 행렬을 사용하여 구간합을 빠르게 계산할 수 있도록 한다.
수열은 오름차순으로 정렬되어 있고, 연속된 수열의 합을 계산하기 때문에
두 개의 포인터를 사용하여 목표 값 k 를 찾도록 한다
앞쪽 포인터는 그대로 두고 뒤쪽 포인터를 이동시켜가며 k 값에 가까워지는지 확인한다
만약 구간 합이 k 보다 작다면 더 큰 수가 필요한 것 이기 때문에 뒤쪽 포인터를 더 뒤로 이동시킨다
만약 구간 합이 k 보다 크다면 구간 내에서 일정 값을 덜어내야 하기 때문에 작은 값들을 먼저 버리도록 앞쪽 포인터를 뒤로 이동시킨다
만약 구간 합이 k 인 지점을 찾았다면 정답을 기록한다.
이 때 구간합에 사용된 요소 개수가 작은 구간을 선택하도록 한다.
Javascript 코드
function solution(sequence, k) {
var candidate = [];
// s는 시작인덱스, e는 끝인덱스
let s = 0,
e = 0;
let sum = sequence[0];
while(e < sequence.length) {
if(sum < k) sum += sequence[++e];
if(sum > k) sum -= sequence[s++];
if(sum == k) {
candidate.push([s, e]);
sum += sequence[++e];
sum -= sequence[s++];
}
}
// candidate를 부분수열의 사이즈가 작은 순서대로 정렬
candidate.sort((next, prev) => (next[1] - next[0]) - (prev[1] - prev[0]));
const filtered = candidate.filter(c => c[1] - c[0] === candidate[0][1] - candidate[0][0]).sort((next, prev) => next[0] - prev[0])
return filtered[0]
}
Python 코드
Python으로는 조금 다른 접근 방식으로 풀었는데, 그 풀이는 다음과 같다.
from collections import defaultdict
def solution(sequence, k):
#prefix_sum: 구간합을 기록하는 배열
#sum_map: 구간합이 나온 sequence의 인덱스를 기록하는 딕셔너리
prefix_sum = [0]
sum_map = defaultdict(int)
sum_map[0] = 0
index = 1
for n in sequence:
cursum = prefix_sum[-1] + n
prefix_sum.append(cursum)
sum_map[cursum] = index
index += 1
#구간합 배열을 순회하면서 모자란 값을 찾으면 answer를 업데이트
answer = [0, 0]
minlen = 9999999
for idx, n in enumerate(prefix_sum):
if n >= k:
#need: 빼야하는 값
need = n - k
if need != 0 and sum_map[need] == 0:
del(sum_map[need])
pass
else:
comp = idx - sum_map[need]
if minlen > comp:
minlen = comp
answer = [sum_map[need], idx-1]
return answer