双端队列
滑动窗口内最大数
题目来源
LeetCode 239. Sliding Window Maximum
精简解题
方法一
-
构建大顶堆,大小为窗口大小k
-
窗口内数据入堆,返回最大值
-
窗口移动,提测内部移除数据,加入新入窗口数据,返回堆顶最大值
-
循环以上步骤,直到结束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
// idx -> 2*idx+1, 2*idx+2 // (idx-1)/2 -> idx func heappush(w []int, val int) []int { var idx, idxN int = len(w), 0 w = append(w, val) for idx > 0 { idxN = (idx - 1) / 2 if w[idxN] < w[idx] { w[idx], w[idxN] = w[idxN], w[idx] } else { break } idx = idxN } return w } func heappop(w []int) ([]int, int) { var idx, idxN int = 0, 0 val := w[0] w[0] = w[len(w)-1] w = w[:len(w)-1] for idx < len(w) { idxN1, idxN2 := 2*idx+1, 2*idx+2 if idxN1 >= len(w) || w[idxN1] < w[idx] { idxN1 = 0 } if idxN2 >= len(w) || w[idxN2] < w[idx] { idxN2 = 0 } if idxN1 > 0 && idxN2 > 0 { if w[idxN1] > w[idxN2] { idxN = idxN1 } else { idxN = idxN2 } } else if idxN1 > 0 { idxN = idxN1 } else if idxN2 > 0 { idxN = idxN2 } else { break } w[idx], w[idxN] = w[idxN], w[idx] idx = idxN } return w, val } func maxSlidingWindow(nums []int, k int) []int { if k == 0 { return []int{} } var window []int = make([]int, 0, k) var dels []int = make([]int, 0) var ans []int = make([]int, 0, len(nums)-k+1) for i := 0; i < k; i++ { window = heappush(window, nums[i]) } ans = append(ans, window[0]) for i := k; i < len(nums); i++ { window = heappush(window, nums[i]) dels = heappush(dels, nums[i-k]) for len(dels) > 0 && dels[0] == window[0] { window, _ = heappop(window) dels, _ = heappop(dels) } ans = append(ans, window[0]) } return ans }
方法二
-
构建双端队列
-
保持队列大小不超过窗口,以及最大值在出端
-
读取新数据,入端操作,和之前的进入的数据比较,之前的数据小则剔除,直到比它大则停止,最大值还在出端
-
循环上面步骤,直到结束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
func maxSlidingWindow(nums []int, k int) []int { //返回值 result := make([]int, 0, len(nums)-k) //滑动窗口 window := make([]int, 0) for i := 0; i < len(nums); i++ { //双端队列的大小超过窗口大小k,则丢弃最早的值 if len(window) > 0 && window[0] <= i-k { window = window[1:] } //新加入的值和之前加入的值比较,没有新值大的则出去 for len(window) > 0 && nums[window[len(window)-1]] < nums[i] { window = window[:len(window)-1] } //双端队列,入口增加数据 window = append(window, i) //开始存入最大值 if i >= k-1 { result = append(result, nums[window[0]]) } } return result }