취미가 좋다

239. Sliding Window Maximum 본문

알고리즘 문제풀이/Leetcode

239. Sliding Window Maximum

benlee73 2021. 9. 28. 11:25

https://leetcode.com/problems/sliding-window-maximum/submissions/

 

Sliding Window Maximum - LeetCode

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.

leetcode.com

Solution

import heapq
from collections import defaultdict

class Solution:
    def maxSlidingWindow(self, nums, k):
        ans = [max(nums[:k])]
        pq = []
        out = defaultdict(int)

        for i in range(k):
            heapq.heappush(pq, (-nums[i], nums[i]))
        
        idx = k
        while idx < len(nums):
            heapq.heappush(pq, (-nums[idx], nums[idx]))
            out[nums[idx-k]] += 1

            while True:
                top = heapq.heappop(pq)[1]
                if out[top] == 0:
                    heapq.heappush(pq, (-top, top))
                    break
                out[top] -= 1

            ans.append(top)
            idx += 1
        return ans
  • ans는 각 window에서 최대값이 들어간다.
  • pq는 heapqueue로 사용될 리스트이다.
  • out은 윈도우가 지나가 고려되지 않아야할 수가 저장된다.
  • 첫 for문으로 pq에 window 사이즈 만큼 요소를 넣는다.
    • 최대힙을 구현하기 위해서는 (-n, n)을 넣어서 첫 요소로 정렬되도록 하고, 나중에 뒤에 있는 요소를 꺼내 쓴다.
  • while문을 돌면서 window를 하나씩 옆으로 옮긴다.
    • 옮기면서 오른쪽 요소는 pq에 추가하고 왼쪽 요소는 out에 추가한다.
    • while을 한 번 더 돌면서 top이 out에 있는 지 확인한다.
    • 없으면 빠져나오고 있으면 out에 체크하고 다음 top을 다시 뽑는다.
  • 그렇게 나온 top을 ans에 넣고 idx를 증가
  • O(NlogN) 시간 복잡도를 가진다.

 

  • while idx < len(nums): 를 하더라도 nums의 길이를 계속 계산하지 않는다. 리스트 자체에 길이 정보를 가지고 있으므로 len(nums)의 시간 복잡도는 O(1)이다.

Another 1

from collections import deque
class Solution(object):
    def add_to_dq(self, dq, nums, i):
        while len(dq) and nums[dq[-1]] <= nums[i]:
            dq.pop()
        dq.append(i)
        return

    def maxSlidingWindow(self, nums, k):
        dq = deque()
        for i in range(k):
            self.add_to_dq(dq, nums, i)

        result, start, end = [nums[dq[0]]], 1, k

        while end < len(nums):
            self.add_to_dq(dq, nums, end)
            while True:
                if dq[0] >= start:
                    result.append(nums[dq[0]])
                    break
                else:
                    dq.popleft()
            start, end = start+1,end+1
        return result
  • deque를 이용한 코드로 더 빠르다.
  • 가장 먼저 add_to_dq 함수를 사용하여 k크기의 윈도우에서 각 인덱스를 dq에 넣는다.
    • 이 함수는 새로 추가되는 인덱스에 해당하는 수가 이전의 수보다 크다면, 이전의 수는 사용할 일이 없으므로 다 pop 해버린다. 그래서 [8,5,2]에 과 같이 내림차순이 만들어진다.
  • while문을 돌면서 윈도우를 이동시킨다.
    • idx를 넣고 dq의 left에 있는 가장 큰 수의 인덱스가 이미 지난 위치라면 pop 해버린다.
    • 아직 윈도우 내의 수라면 result에 넣고 다음 while문
  • O(N) 시간 복잡도를 가진다.

Another 2

from collections import deque
class Solution(object):
    def maxSlidingWindow(self, nums, k):
        dq = deque()
        out = []
        for i, n in enumerate(nums):
            while dq and nums[dq[-1]] < n:
                dq.pop()
                
            dq += i,

            if dq[0] == i - k:
                dq.popleft()

            if i >= k - 1:
                out += nums[dq[0]],
        return out
  • 위와 같이 deque를 사용했고 코드도 더 간결하고 빠르다.
  • dq에 요소가 있고 dq의 마지막이 윈도우가 이동하면서 추가될 요소보다 작은 것들은 pop한다. (위와 동일하게 내림차순이 만들어진다.)
  • dq += i, 를 통해서도 deque에 값을 추가할 수 있다. 콤마가 필수이다.
  • dq의 처음이 윈도우에서 지나온 곳이라면 pop 한다.
  • index가 k-1을 넘는 순간부터 out에 값을 추가한다.

 

  • 내가 푼 방식은 heapq, defaultdict만 사용하면 되므로 lev3 정도의 풀이법
  • 다른 사람들의 방식으로는 deque를 잘 사용하는 lev4 정도의 풀이법

'알고리즘 문제풀이 > Leetcode' 카테고리의 다른 글

31. Next Permutation  (0) 2021.10.08
240. Search a 2D Matrix II  (0) 2021.10.02
238. Product of Array Except Self  (0) 2021.09.24
236. Lowest Common Ancestor of a Binary Tree  (0) 2021.09.22
230. Kth Smallest Element in a BST  (0) 2021.09.07
Comments