새소식

PS/LeetCode

632. Smallest Range Covering Elements from K Lists

  • -

Problem : https://leetcode.com/problems/smallest-range-covering-elements-from-k-lists

 

Difficulty : Hard

 

Status : Solved

 

Time : 00:18:12

 


 

문제 설명

 

더보기

k개의 단조증가하는 순서(감소하지 않는 순서)로 정렬된 리스트를 가지고 있다. k개의 리스트 각각의 적어도 하나의 수를 포함하는 가장 작은 범위를 구하여라.

 

우리는 다음 상황 ( b-a < d-c 거나, b-a == d-c이면서 a<c일때) 범위 [a, b]가 범위 [c, d]보다 작다고 정의한다.


 

풀이

 

쪼오금 마음에 안드는 풀이긴 하지만, 이렇게 풀 수 있다! 를 보려주려고 한다.

 

슬라이딩 윈도우를 생각해 보자. 이 슬라이딩 윈도우는 가급적 k개 집합의 모든 수를 최소한으로 보유하는 게 목적이다. 즉 다음 기능이 필요하다.

  • 숫자와 인덱스 정보를 저장할 큐
  • 덱에 각 리스트의 숫자를 얼마나 보유하고 있는지 저장할 리스트

 

또한, 우리는 입력받은 k개 리스트를 하나로 합치고 정렬할 것이다(이 때 각 숫자는 원본 리스트의 정보를 가지고 있다 - 즉 숫자, 리스트 번호 형태의 튜플이라고 생각하자)..

 

이제 nums를 순회할 텐데, 다음 과정을 수행한다.

  • 슬라이딩 윈도우 큐에 nums와 index 정보를 추가한다.
  • 슬라이딩 윈도우가 커버 조건(k개의 모든 리스트의 숫자를 모두 보유하고 있는지)을 만족하지 않을 때까지, 슬라이딩 윈도우 큐를 pop한다.
  • 마지막 pop 직전의 구간이 정답 후보가 될 수 있는 구간(오른쪽에 num, idx일 때의 최소 구간)이므로, 최소 구간을 비교하며 확인한다.

k <= 3500, 한 리스트의 길이 <= 50이므로 한 번의 순회로 충분히 짧은 시간 내에 정답을 얻을 수 있다.

 

풀이 코드

class SlidingWindow:
    def __init__(self, k):
        self.total = 0
        self.count = [0]*k
        self.k = k
        self.queue = deque()
    def push(self, num, idx) :
        if not self.count[idx] :
            self.total += 1
        self.count[idx] += 1
        self.queue.append((num, idx))
    def pop(self) :
        num, idx = self.queue.popleft()
        self.count[idx] -= 1
        if not self.count[idx] :
            self.total -= 1
    def coverLength(self) :
        if not self.total == self.k :
            return [-1, -1]
        return [self.queue[0][0], self.queue[-1][0]]

class Solution:
    def smallestRange(self, nums: List[List[int]]) -> List[int]:
        k = len(nums)
        slidingWindow = SlidingWindow(k)
        nums = [(i, j) for j in range(k) for i in nums[j]]
        nums.sort()
        result = [nums[0][0], nums[-1][0]]

        for num, idx in nums :
            slidingWindow.push(num, idx)
            minLen = [-1, -1]
            while True :
                tmp = slidingWindow.coverLength()
                if tmp == [-1, -1] :
                    break
                minLen = tmp
                slidingWindow.pop()
            if minLen != [-1, -1] and minLen[1] - minLen[0] < result[1] - result[0] :
                result = minLen
        return result

'PS > LeetCode' 카테고리의 다른 글

2044. Count Number of Maximum Bitwise-OR Subsets  (0) 2024.10.18
670. Maximum Swap  (0) 2024.10.18
1942. The Number of the Smallest Unoccupied Chair  (0) 2024.10.11
962. Maximum Width Ramp  (0) 2024.10.10
921. Minimum Add to Make Parentheses Valid  (0) 2024.10.09
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.