백준 1806 - 부분합 (Python3)
코드
# 최댓값
INF = int(1e9)
n, s = map(int, input().split())
arr = list(map(int, input().split()))
# 처음과 끝이 동일한 지점일 수 있음
start = 0
end = 0
# 부분합을 담을 변수
parts = 0
# 최종 정답을 담을 변수 (최소 개수를 담을 것이므로 INF로 초기화)
answer = INF
# end가 배열의 마지막에 도달할 때까지 반복 실시
while True:
# 부분 수열의 길이
# end-start-1이 아닌 이유
# 직전의 연산에서 end는 +1이 증가한다 => 별도로 +1을 해줄 필요가 없음
length = end - start
# 부분합이 s보다 크다면
if parts >= s:
# print(start, end, length, parts, answer)
# s보다 큰 경우의 부분 수열 길이를 구하는 것이므로
# length와 answer 중 더 작은 값으로 answer를 업데이트 시킴
answer = min(answer, length)
# 아래 두 코드를 작성하는 이유
# => 부분합이 큰 첫 구간을 구하는게 아니라 끝까지 구해서 가장 짧은 길이를 구해야 함
# => answer의 값이 업데이트 됐어도 다음 요소들이 남아있다면 부분합을 계속 갱신해줘야 함
# 부분합에 맨 첫 요소의 값만큼 감소
parts -= arr[start]
# 첫 요소를 뺌 => start값을 1증가 시킴
start += 1
# end가 n과 값이 같아짐
# => 배열의 마지막(n-1)까지도 다 반복을 실시했음
# => 끝까지 부분합을 다 구했음
elif end == n:
break
# s보다 작거나 같다면
else:
# 부분합에 마지막 요소를 더 해줌
parts += arr[end]
# end값 1증가
end += 1
# answer의 값이 변경되지 않으면 INF => 0 출력
if answer == INF:
print(0)
else:
print(answer)
문제 해설
부분합을 투 포인터를 활용하여 해결하는 문제.
투 포인터 자체가 단순하여 쉽게 생각했다가 상당히 애를 먹은 문제이다. 로직 자체는 구현을 하였으나 아래의
# end가 n과 값이 같아짐
# => 배열의 마지막(n-1)까지도 다 반복을 실시했음
# => 끝까지 부분합을 다 구했음
elif end == n:
break
이 분기를 파악하지 못해서 계속 오답 처리를 받았다. 결국 구글링으로 위와 같은 코드를 파악하여 한 줄 한 줄 별도의 공부를 하여 문제를 풀 수 있었다.
또한, 부분 수열의 길이를 담을 변수 length를 구하는 식이 end - start인 것도 이해하는데 시간이 걸렸다. 실제 만약 start가 1이고 end가 3인 경우, 부분 수열의 길이는 3-1+1 인 3이 되어야 한다. 허나, 코드에서 보면
length = end - start
위와 같이 계산하였다. 이유는 목푯값인 s보다 부분합의 값이 커지기 바로 직전의 조건문 연산인
# s보다 작거나 같다면
else:
# 부분합에 마지막 요소를 더 해줌
parts += arr[end]
# end값 1증가
end += 1
위의 코드에 있다. 코드를 보면 부분합을 증가시킨 후, end의 값 또한 1 증가하게 된다. 이런 경우, 당연히 부분합에 누적된 값은 arr[end-1]까지 누적돼있지만, 마지막 지점의 값은 end 즉, +1이 추가된 상태이다. 이 로직 후, s보다 부분합의 값이 커졌다면 다음은 아래의 조건문이 동작하게 된다.
length = end - start
# 부분합이 s보다 크다면
if parts >= s:
# s보다 큰 경우의 부분 수열 길이를 구하는 것이므로
# length와 answer 중 더 작은 값으로 answer를 업데이트 시킴
answer = min(answer, length)
# 부분합에 맨 첫 요소의 값만큼 감소
parts -= arr[start]
# 첫 요소를 뺌 => start값을 1증가 시킴
start += 1
즉, end는 다음 연산을 위해 미리 1이 증가된 상태이므로 length 자체가 end - start + 1이 아닌 end - start로 구해야 하는 것이다.
알고리즘을 사용해서 구현을 하는 그 과정이 생각보다 많이 까다로웠다. 여러번 반복하여 문제를 계속하여 풀어봐야겠다.
댓글남기기