算法题:滑动窗口的最大值

77 阅读1分钟

滑动窗口的最大值

难度困难

给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。

示例:

输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7] 
解释: 
  滑动窗口的位置                最大值
---------------               -----
[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

此题有各种差解和次优解,最优解是单调队列,是一个动态的单调队列,遍历过程会操作这个单调队列,保证:

  1. 队列单调递减
  2. 队列头最大值的下标如果滑出窗口最小下标就移出队列

也就是保存了上一个窗口最大的值,和次大的值,和次次大的值,如果最大移出了,也能取到次大的值,来构建新的队列。


  滑动窗口的位置                单调队列
---------------               -----
[1  3  -1] -3  5  3  6  7       3 -1
 1 [3  -1  -3] 5  3  6  7       3 -1 -3 
 1  3 [-1  -3  5] 3  6  7       5 
 1  3  -1 [-3  5  3] 6  7       5  3
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

代码如下:

class Solution {
    fun maxSlidingWindow(nums: IntArray, k: Int): IntArray {
        var result = IntArray(nums.size - k + 1)
        var list = LinkedList<Int>()
        for (i in 0..nums.size - 1) {
        
            //队列头最大值的下标如果滑出窗口最小下标就移出队列
            if (!list.isEmpty() && list.first < i - k + 1) {
                list.removeFirst()
            }

            //队列单调递减
            while (!list.isEmpty() && nums[list.last] < nums[i]) {
                list.removeLast()
            }
            list.add(i)
            if (i >= k - 1) {
                result[i - k + 1] = nums[list.first]
            }
        }
        return result;
    }
}