최대 백색 타일 수 계산: 슬라이딩 윈도우와 경계 조건 처리

문제 해결을 위해 배열을 사용하려 했으나 메모리 초과가 발생하여, 원본 데이터를 직접 수정하며 슬라이딩 윈도우 방식으로 접근했다. 특히 경계 조건 처리는 항상 어려운 부분이지만, 핵심은 구간 커버리지 문제에서 각 구간의 우측 끝점을 기준으로 왼쪽으로 확장 가능한 최대 길이를 탐색하는 것이다.

주요 전략은 다음과 같다:

  • 먼저 타일의 시작 위치 기준으로 정렬한다.
  • 왼쪽 포인터를 유지하면서, 현재 오른쪽 포인터가 가리키는 구간의 끝점까지의 총 덮개 길이를 누적한다.
  • 현재 카펫 길이로 왼쪽 구간이 완전히 커버되지 않으면, 왼쪽 포인터를 이동시키며 커버되지 않는 부분을 제거한다.
  • 그 후, 겹치지 않는 부분(카펫 범위 밖)을 계산해 전체 커버리지에서 빼서 최댓값 갱신.
class Solution {
public:
    int maximumWhiteTiles(vector<vector<int>>& tiles, int carpetLen) {
        sort(tiles.begin(), tiles.end());
        int left = 0;
        int covered = 0;
        int result = 0;

        for (auto& tile : tiles) {
            int start = tile[0];
            int end = tile[1];

            covered += end - start + 1;

            // 현재 카펫이 왼쪽 구간의 끝보다 앞선 경우, 왼쪽 포인터 이동
            while (tiles[left][1] + carpetLen - 1 < end) {
                covered -= tiles[left][1] - tiles[left][0] + 1;
                left++;
            }

            // 카펫이 겹치지 않는 부분 계산 (음수 방지)
            int uncovered = max(end - carpetLen + 1 - tiles[left][0], 0);
            result = max(result, covered - uncovered);
        }

        return result;
    }
};

슬라이딩 윈도우 문제에서는 반드시 정렬이 첫 단계다. 이 문제는 두 차원의 구간을 다루므로, 포인터는 단순한 인덱스가 아니라 vector<int>& 형태의 구간을 의미한다.

또한, 유사한 유형의 문제인 "최대 과일 수 수확" (LeetCode 2306)을 참고하면, 더 깔끔한 슬라이딩 윈도우 구현이 가능하다. 아래는 영신님의 간결한 코드 예시이다:

class Solution {
public:
    int maxTotalFruits(vector<vector<int>>& fruits, int startPos, int k) {
        int left = lower_bound(fruits.begin(), fruits.end(), startPos - k, 
                              [](const auto& a, int val) { return a[0] < val; }) - fruits.begin();
        int right = left, sum = 0, n = fruits.size();

        // startPos 이전까지의 과일 수 누적
        while (right < n && fruits[right][0] <= startPos) {
            sum += fruits[right][1];
            right++;
        }

        int ans = sum;

        // 오른쪽으로 확장하며 최대값 갱신
        while (right < n && fruits[right][0] <= startPos + k) {
            sum += fruits[right][1];
            // 왼쪽 구간이 도달 불가능한 경우, left 포인터 이동
            while (fruits[right][0] * 2 - fruits[left][0] - startPos > k &&
                   fruits[right][0] - fruits[left][0] * 2 + startPos > k) {
                sum -= fruits[left][1];
                left++;
            }
            ans = max(ans, sum);
            right++;
        }

        return ans;
    }
};

이 코드는 시간 복잡도를 효율적으로 관리하며, 조건에 따라 왼쪽 포인터를 적절히 이동시켜 최적의 해를 찾는다.

태그: sliding window interval coverage Two Pointers sorting LeetCode

7월 27일 06:37에 게시됨