백준 1806 : 부분합 (Python)

CHEDDAR·2025년 4월 30일

알고리즘

목록 보기
9/24

백준 1806 문제

문제

10,000 이하의 자연수로 이루어진 길이 N짜리 수열이 주어진다. 이 수열에서 연속된 수들의 부분합 중에 그 합이 S 이상이 되는 것 중, 가장 짧은 것의 길이를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N (10 ≤ N < 100,000)과 S (0 < S ≤ 100,000,000)가 주어진다. 둘째 줄에는 수열이 주어진다. 수열의 각 원소는 공백으로 구분되어져 있으며, 10,000이하의 자연수이다.

출력

첫째 줄에 구하고자 하는 최소의 길이를 출력한다. 만일 그러한 합을 만드는 것이 불가능하다면 0을 출력하면 된다.

예제 입력 1

10 15
5 1 3 5 10 7 4 9 2 8

예제 출력 1

2


나의 풀이

  • 10<=N<=100,000이고 0<=S<=100,000,000이기에 슬라이딩 윈도우 알고리즘으로 풀이하면 시간 초과가 발생할 수 있다. 따라서 윈도우의 크기가 고정되지 않은 투 포인터 알고리즘으로 구현해 시간 복잡도를 낮추는 것이 핵심이다. 이 문제는 연속된 수열의 구간합을 투 포인터 알고리즘으로 계산하는 것으로 아래 그림과 같은 순서로 포인터가 이동한다.
  • 오랜만에 투 포인터 알고리즘을 직접 구현하려니 포인터 위치 설정, 구간합 계산 등의 과정에서 사고가 꼬여 풀이에 시간이 꽤 소요되었다. (left,right) 포인터의 위치는 (left+1,right) 또는 (left,right+1)로 변할 수 있는데 변한 후의 total을 어떻게 계산할 지가 관건이었다. right => right+1 은 단순히 right 포인터가 가르키는 새로운 위치의 원소값을 total에 더해주면 되고, left=> left+1은 기존 total에서 left 위치의 원소값을 total에서 빼도록 구현했다.

예제 1 기준 포인터 이동 순서

import sys

N, S = map(int, sys.stdin.readline().split())
seq = list(map(int, sys.stdin.readline().split()))

def cal(N, S, seq):
    left = 0
    total = 0
    answer = N + 1 

    for right in range(N):
        total += seq[right]
        while total >= S:
            answer = min(answer, right - left + 1)
            total -= seq[left]
            left += 1
            
    if answer!=N+1:
        return answer 
    else:
        return 0 

print(cal(N, S, seq))
profile
SAY CHEESE

0개의 댓글