leetcode 长度最小的子数组 && 实现一个最大堆

148 阅读2分钟

209. 长度最小的子数组

leetcode-cn.com/problems/mi…

  • 滑动窗口
    • 用来解决一些查找满足一定条件的连续区间的性质问题,当区间发生变化时,可以通过旧有的计算结果对搜索空间进行剪枝,减少重复的计算量,降低算法时间复杂度
    • 扩张窗口:为了找到一个可行解,找到了就不再扩张
    • 收缩窗口:在长度上优化该可行解,直到条件被破坏
    • 寻找下一个可行解,然后再优化到不能优化……
/**
 * @param {number} s
 * @param {number[]} nums
 * @return {number}
 */
var minSubArrayLen = function(s, nums) {
    let sum = 0
    let counter = Number.MAX_SAFE_INTEGER
    let left = 0 
    for(let right=0;right<nums.length;right++){
        sum = sum + nums[right]
        while(sum >= s){
            counter = Math.min(counter,right-left+1)            
            sum = sum - nums[left]
            left++
        }
    }
    return counter === Number.MAX_SAFE_INTEGER ? 0 : counter
};

实现一个最大堆

  • 定义
    • 二叉堆是一颗完全二叉树
    • 堆中某个节点的值总是不大于其父节点的值(最大堆),相反的定义则是最小堆
  • 性质(由数组实现)
    • 左子树头节点的 index = 2 * k + 1
    • 右子树头节点的 index = 2 * k + 2
    • 父亲节点的 index = Math.floor((k - 1) / 2)
  • 应用
    • 实现堆排序
    • 实现优先队列
class MaxHeap {

    data = []
    constructor(data = []) {
        this.data = data
        for (let i = this.getParent(this.getSize() - 1); i >= 0; i--) {
            this.siftDown(i)
        }
    }

    isEmpty() {
        return this.data.length === 0
    }

    getSize() {
        return this.data.length
    }

    add(e) {
        this.data.push(e)
        this.siftUp(this.getSize() - 1)
    }

    findMax() {
        return this.data[0]
    }
    // 删除最大的元素
    removeMax() {
        const max = this.findMax()
        this.swap(0, this.getSize() - 1)
        this.data.pop()
        this.siftDown(0)
        return max
    }
    // 获取该元素的父节点index
    getParent(k) {
        return Math.floor((k - 1) / 2)
    }

    // 获取该元素的左孩子index
    getLeftChild(k) {
        return 2 * k + 1
    }

    // 获取该元素的右孩子index
    getRightChild(k) {
        return 2 * k + 2
    }

    swap(k1, k2) {
        const temp = this.data[k1]
        this.data[k1] = this.data[k2]
        this.data[k2] = temp
    }
    // 上浮 使其满足最大堆定义
    siftUp(k) {
        while (k > 0 && this.data[k] > this.data[this.getParent(k)]) {
            this.swap(k, this.getParent(k))
            k = this.getParent(k)
        }
    }
    // 下沉 使其满足最大堆定义
    siftDown(k) {
        while (this.getLeftChild(k) < this.getSize()) {
            const left = this.getLeftChild(k)
            const right = this.getRightChild(k)
            let maxIndex = left
            if (right < this.getSize() && this.data[left] < this.data[right]) {
                maxIndex = right
            }

            if (this.data[k] > this.data[maxIndex]) {
                break
            }
            this.swap(k, maxIndex)
            k = maxIndex

        }
    }
    // 将最大堆的顶点元素换成另一个元素
    replace(e) {
        const max = this.findMax()
        this.data[0] = e
        this.siftDown(0)
        return max
    }

}