[LeetCode] 239. Sliding Window Maximum(滑动窗口的最大值)
- Difficulty: Hard
- Related Topics: Heap, Sliding Window, Dequeue
- Link: https://leetcode.com/problems/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
-
How about using a data structure such as deque (double-ended queue)?
试试使用像双向队列这样的数据结构? -
The queue size need not be the same as the window's size.
队列的大小不需要和窗口大小相等。 -
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()
}
}