Loading

[LeetCode] 239. Sliding Window Maximum(滑动窗口的最大值)

Description

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.
给定一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左端移动到最右端。你只能看见窗口内的 k 个数。滑动窗口每次向右移动一个单位。

Return the max sliding window.
返回每个滑动窗口的最大值。

Examples

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

Example 2

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

Example 3

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

Example 4

Input: nums = [9,11], k = 2
Output: [11]

Example 5

Input: nums = [4,-2], k = 2
Output: [4]

Constraints

  • 1 <= nums.length <= 1e5
  • -1e4 <= nums[i] <= 1e4
  • 1 <= k <= nums.length

Hints

  1. How about using a data structure such as deque (double-ended queue)?
    试试使用像双向队列这样的数据结构?

  2. The queue size need not be the same as the window's size.
    队列的大小不需要和窗口大小相等。

  3. Remove redundant elements and the queue should store only elements that need to be considered.
    移除多余的元素,队列里只保存需要被考虑的元素。

Solution

以下解法来自我的一本算法书:

题目的提示告诉我们使用双端队列,为什么不用普通队列?因为双端队列可以从队尾添加,删除元素。我们希望队首永远是窗口的最大值,那自然只能在入队的时候队元素作筛选了。需要注意的是,我们在双端队列里存的是元素下标而非元素本身,这是为了方便清理失效的最大值。队列的维护规则如下:

  • 插入规则:队列为空时直接插入,否则比较队尾对应的元素与当前元素,若当前元素更大,则不断从队尾弹出元素,直到当前元素小于队尾对应元素,然后将该元素的下标入队。
  • 取最大值的规则:若队首元素超出窗口范围,则弹出该元素,否则,队首对应元素即为当前窗口的最大值。

代码如下:

class Solution {
    fun maxSlidingWindow(nums: IntArray, k: Int): IntArray {
        if (k == 1) {
            return nums
        }
        if (k >= nums.size) {
            return intArrayOf(nums.max()!!)
        }

        val maxIndices: Deque<Int> = ArrayDeque()
        val result = arrayListOf<Int>()

        for (i in nums.indices) {
            while (maxIndices.isNotEmpty() && nums[maxIndices.peekLast()] <= nums[i]) {
                maxIndices.pollLast()
            }
            maxIndices.offerLast(i)
            if (maxIndices.peekFirst() == i - k) {
                maxIndices.pollFirst()
            }
            if (i >= k - 1) {
                result.add(nums[maxIndices.peekFirst()])
            }
        }

        return result.toIntArray()
    }
}
posted @ 2020-12-21 10:04  Zhongju.copy()  阅读(89)  评论(0编辑  收藏  举报