프로그래밍/알고리즘

no.30804 과일 탕후루

데일리 백수 2025. 1. 9. 22:32
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;


int main()
{
    int N;
    cin >> N;
    vector<int> S(N);
    for (int i = 0; i < N; i++) {
        cin >> S[i];
    }

    vector<int> count(10, 0);
    int distance = 0;
    int left = 0, answer = 0;

    for (int right = 0; right < N; right++) {
        int fruitR = S[right];

        if (count[fruitR] == 0)distance++;
        count[fruitR]++;

        while (distance>2)
        {
            int fruitL = S[left];
            count[fruitL]--;
            if (count[fruitL] == 0) distance--;
            left++;
        }

        answer = max(answer, right - left + 1);

    }

   
    cout << answer;

}

 

문제 분석

주어진 N의 배열에서 연속된 부분중에 과일의 종류가 2가지 이하인 부분부열의 최대길이를 구하여라 

즉 부분탐색, 투포인터 슬라이딩 윈도우를 사용하여 푸는 문제이다. 

 

왜 슬라이딩 윈도우일까?

문제에서 앞에서 a개 뒤에서 b개 버리고 중간 구간을 쓰겠다. 라고 정의했다.

이는 절차적으로 1개씩 버려가며 확인할 수 없다. (앞 1개 버리고 뒤1개 버리고는 답없음)

배열의 연속구간을 정한후, 연속구간이 해당 조건을 만족하는지 검사하며 풀어야한다.

 

풀이 설계

left, right 두 포인터를 0부터 시작

right를 오른쪽으로 1씩 이동하며 구간을 확장

구간안의 과일 종류가 2를 초과하면 left를 오른쪽으로 이동시키면서 종류수가 2 이하가 될 떄까지 조정

매 단계에서 2이하기 유지되는 구간 길이를 업데이트 해준다. 

  vector<int> count(10, 0);
  int distance = 0;
  int left = 0, answer = 0;

  for (int right = 0; right < N; right++) {
      int fruitR = S[right];

      if (count[fruitR] == 0)distance++;
      count[fruitR]++;

      while (distance>2)
      {
          int fruitL = S[left];
          count[fruitL]--;
          if (count[fruitL] == 0) distance--;
          left++;
      }

      answer = max(answer, right - left + 1);

  }

 

이 부분을 예제와 함께 살펴보자

 

5
5 1 1 2 1

을 입력했을 때

 

left =0 right =0일때 

fruitR은 5, 길이는 1이된다. 000010000

그후 right를 증가시킴

answer은1

 

left =0 right =1일때 

fruitR은 1, 길이는 2이된다. 100010000

그후 right를 증가시킴 

answer은2

 

left =0 right =2일때

fruitR은 1, 길이는 2이된다. 200010000

그후 right를 증가시킴

answer은3

 

left =0 right =3일때

fruitR은 2, 길이는 3이된다. 210010000

 while (distance>2)
 {
     int fruitL = S[left];
     count[fruitL]--;
     if (count[fruitL] == 0) distance--;
     left++;
 }

 

이 블럭에 진입하게 됨

fruitL = 5 가 되고 210000000

count 배열의 5번째가 0이므로 left를 하나 증가

즉 left=1 right=3

answer은3

 

left =1 right=4일때

fruitR은 1 길이는 2가된다 310000000

그후 right를 증가시킴 (종료)

answer는 4로 갱신 

 

범위 설정과 관리, 범위 갱신조건을 잘 설정하면 쉽게 풀수있는 문제이다.