Sliding Window Maximum

145 阅读1分钟

题目描述

leetcode.com/problems/sl…

分析

如果直接 brute force, 会导致超时,所以本题的优化在于怎么保存窗口的值,我这里采取的是 heap 的套路

解题思路

用 heap 存窗口值
滑动过程中做两件事:取最大,heap insert 窗口右端,如果 top 值是滑出去的则 extract

过程

声明堆 heap,先存 k
声明变量 left 作为窗口左端

开始滑动

每次记录 top value,如果 top value 不合法,则先弹出,知道找到一个合适的

代码

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number[]}
 */
var maxSlidingWindow = function(nums, k) {
    const n = nums.length
    let win = []
    const h = new Heap((a, b) => {
        if (!b) return false
        return a[1] < b[1]
    })
    // put k items initially to heap
    let cnt = k, l = 0
    while (cnt--) {
        h.insert([l, nums[l]])
        l++
    }
    win.push(h.top()[1])
    
    let left = 1
    while (left < n) {
        const r = left + k - 1
        if (r >= n) break
        console.log(left, r)
        h.insert([r, nums[r]])
        
        while (h.top()[0] < left) h.extract()
        win.push(h.top()[1])
        
        left++
    }
    
    return win
};

class Heap {
    constructor(compareFn) {
        this.heap = []
        this.compareFn = compareFn
    }
    
    getLeftIndex(index) {
        return index * 2 + 1
    }
    
    getRightIndex(index) {
        return index * 2 + 2
    }
    
    getParentIndex(index) {
        return Math.floor((index - 1) / 2)
    }
    
    size() {
        return this.heap.length
    }
    
    isEmpty() {
        return this.size() === 0
    }
    
    swap(parent, index) {
        const arr = this.heap;
        ;[arr[parent], arr[index]] = [arr[index], arr[parent]]
    }
    
    insert(value) {
        const index = this.heap.length
        this.heap.push(value)
        this.siftUp(index)
    }
    
    siftUp(index) {
        let parent = this.getParentIndex(index)
        
        while (index > 0 && this.compareFn(this.heap[parent], this.heap[index])) {
            this.swap(parent, index)
            index = parent
            parent = this.getParentIndex(index)            
        }
    }
    
    extract() {
        if (this.isEmpty()) return
        if (this.size() === 1) return this.heap.pop()
        
        const removedItem = this.heap[0]
        this.heap[0] = this.heap.pop()
        this.siftDown(0)
        
        return removedItem
    }
    
    siftDown(index) {
        let element = index
        const left = this.getLeftIndex(index)
        const right = this.getRightIndex(index)
        
        if (index < this.size() && this.compareFn(this.heap[element], this.heap[left])) element = left
        if (index < this.size() && this.compareFn(this.heap[element], this.heap[right])) element = right
        
        if (index !== element) {
            this.swap(element, index)
            this.siftDown(element)
        }
    }
    
    top() {
        return this.heap[0]
    }
}