算法练习Day11 (Leetcode/Python-堆栈和队列)

239. Sliding Window Maximum

You are given an array of integers nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.

Return the max sliding window.

Example 1:

Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [3,3,5,5,6,7]
Explanation: 
Window position                Max
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

思路:维护一个长度为当前window长度的单调队列,每次output这个单调队列里最大的值就是所求的值。window每向右挪动1位,push这个值到单调队列里,pop出比这个值小的已在队列里的值,因为这些值永远不会成为最大值了。但是注意当队列最左的元素从window中挪出后,就要从单调队列里也挪出对应的值。以下的第一种方法在挪出左边的元素时,是通过比较实际数值来判断单调队列最左(最大)的值是否是队列最左的值,继而判断队列中是否要挪出。第二种写法里,单调队列中维护的是元素的序号而不是值本身,这样在判断是否需要挪出单调队列中最左(最大)的元素时,用if i-d[0] >= k: d.popleft()即可,感觉更加优雅。

from collections import deque 

class MyQueue: # Monotonic queue # from large to small 
    def __init__(self):
        self.queue = deque() #Using a list would be inefficient over time, so we are using a queue here for bidirectional functionality.
    def pop(self, value):
        if self.queue and value ==self.queue[0]:
            self.queue.popleft() 
    # Push a new value into the queue and remove items smaller than it for a sorted queue 
    def push(self, value):
        while self.queue and value > self.queue[-1]:
            self.queue.pop()
        self.queue.append(value)
    # check the largest value in the queue 
    def front(self):
        return self.queue[0]
    def length(self):
        return len(self.queue)


# 写法1: 对比值来判断是否pop最左的元素
class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        myque = MyQueue()
        result = []
        for i in range(k):
            myque.push(nums[i])
        result.append(myque.front())

        for i in range(k, len(nums)):
            if myque.length() < k:
                myque.push(nums[i])
            else:
                myque.pop(nums[i-k])
                myque.push(nums[i])
            result.append(myque.front())
        return result
# 写法二:存入单调序列的本就是元素的位置序号
class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        d = deque()
        n = len(nums)
        res = []
        
        for i in range(k):
            while d and nums[d[-1]] <= nums[i]:
                d.pop()
            d.append(i)
        res.append(nums[d[0]])

        for i in range(k,n):
            if i-d[0] >= k :
                d.popleft()
            while d and nums[d[-1]] <= nums[i]:
                d.pop()
            d.append(i)
            res.append(nums[d[0]])
        return res

时间复杂度:O(n)

347. Top K Frequent Elements

Given an integer array nums and an integer k, return the k most frequent elements. You may return the answer in any order.

Example 1:

Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]

思路:统计出每类元素的个数后,进行排序。也可以用快排,但没必要对整个序列排序,这里维护一个长度为k的排序就可以了。用min-heap,保证最top上就是最小的值,然后不断pop频率最小的值,直到最后留在heap里的只有k个值,这k个才是出现频率最高的k个值,这时候再对这k个排序即可。

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        # count the occurance of each value
        map_ = {}
        for i in range(len(nums)):
            map_[nums[i]] = map_.get(nums[i], 0) + 1
        
        # Sort the heap in size k
        # The smallest value is on the top
        pri_que = [] 
        for key,freq in map_.items():
            heapq.heappush(pri_que, (freq, key))
            if len(pri_que) > k: # If the size of the heap is larger than k, pop the one with smallest frequency
                heapq.heappop(pri_que)

        # Find the top k highest item. The smallest is popped first so the order is revered for the output.  
        result = [0] * k 
        for i in range(k-1, -1, -1):
            result[i] = heapq.heappop(pri_que)[1]
        return result 

时间复杂度 O(nlogk)。因为 heapq.heappop(pri_que), heapq.heappush(pri_que, (freq, key)) 的复杂度是O(logk),最多有n个元素要被push,复杂度就为O(nlogk)了。len(pri_que)的复杂度是O(1)。

你可能感兴趣的:(算法,leetcode,python)