본문 바로가기
알고리즘&자료구조/투 포인터

백준 1806

by dongR 2024. 2. 1.

1.문제이해

요약 : 길이 N의 수열의 연속된 수들의 부분합에서 그 합이 S 이상이 되면서 가장 짧은 부분합 길이를 출력

ex) N = {5, 10, 7, 4} 이고 S=15 일때, 5 + 10 or 10 + 7 + 4의 부분합을 구할 수 있음

연속된 수들이기 때문에 부분합은 두 개 이상의 연속된 수로 이루어져야 함

2.문제분석

S이상이 되는 부분합을 체크하고 그 부분합의 길이가 가장 짧은 부분합 길이(minLength)라면 해당 길이로 변경

로직

1. st, en 두 개의 커서를 배열의 시작 지점부터 한 칸씩 오른쪽으로 늘리면서 2개 이상의 수의 부분합으로 이루어져 있는가?

2. 부분합이 S 이상인가?

2.1. S이상이라면 부분합의 길이가 minLength 작은가?

2.1.1. minLength 보다 작다면 minLength값을 변경 후

en 커서를 오른쪽으로 늘릴 필요가 없기 때문에 st커서를 오른쪽으로 한 칸 이동

2.1.2. minLength 보다 크다면 st 커서만 오른쪽으로 한 칸 이동

(en 커서를 오른쪽으로 한 칸 이동하면 부분합 길이가 더 커지기 때문)

2.2. 부분합이 S보다 작으면 en 커서를 오른쪽으로 한 칸 이동
(S보다 커야되는 조건을 찾아야 되기 때문에 부분합 길이를 증가시킴)

3. st, en 커서 둘 중에 하나라도 N의 크기를 넘기면 반복문 종료

4. 반복문 종료 후 minLength의 초기값이 변하지 않았다면 부분합이 없는 경우이므로 minLength에 0을 넣어준다.

5. minLength 출력

3.코드

#include <iostream>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);    

    // 입력 
    int N, S;
    cin >> N >> S;    
    int* arr = new int[N];
    for (int i = 0; i < N; i++) {
        cin >> arr[i];
    }

    // 로직    
    int st = 0;
    int en = 0;
    int partSum = arr[0]; // 부분합 초기값     
    int minLength = 0x7fffffff; // 가장짧은 부분합 길이 초기값     

    while (st < N && en < N) {
        // 두 개의 커서 위치를 뺏을 때 1이상인 경우 2개 이상의 부분합으로 이루어져있다는 뜻        
        if (partSum >= S && en - st > 0) {
            if (en - st + 1 < minLength) {
                minLength = en - st + 1;
            }                
            partSum -= arr[st];
            st++;                
        }
        else {
            en++;
            if (en != N) partSum += arr[en];
        }                
    }

    // minLength의 값이 변경되지 않았다면 부분합이 한번도 만들어지지 않았다는 뜻이므로 0을 넣어줌
    if (minLength == 0x7fffffff) minLength = 0;
    cout << minLength;


    return 0;
}

'알고리즘&자료구조 > 투 포인터' 카테고리의 다른 글

백준 2230  (0) 2024.01.30
좋은 수 구하기(백준 1253)  (0) 2024.01.21
주몽의 명령(백준 1940)  (2) 2024.01.18
투 포인터 연속된 자연수의 합(백준 2018)  (2) 2024.01.16