前端就该用 JS 刷算法27

135 阅读1分钟

每日一题 -- 堆

1046. 最后一块石头的重量

1046. 最后一块石头的重量

分析

  1. 因为每一次都是敲碎两颗石头,得到差值,然后再进入到序列中,是动态求极值的需求,可以用堆来处理
  2. 每一次都是求当前最大的两个值,然后求差,如果差不为0,则需要重新插入到堆中,然后再自底向上整理堆
  3. 这里之所以用遍历所有节点向上整理,是因为每一个差值都会往尾部添加,这个时候需要找出堆中的最大值并放在堆顶,就必须要自底向上递归的去处理。
// https://leetcode-cn.com/problems/last-stone-weight/
// 1046. 最后一块石头的重量

var lastStoneWeight = function (stones) {
    // 构建最大堆
    if (stones.length < 1) return 0
    const maxHeap = new Heap(stones.length)
    for (let i = 0; i < stones.length; i++) {
        maxHeap.data[i + 1] = stones[i]
        maxHeap.up(i + 1)
    }

    while (maxHeap.data.length > 1) {
        if (maxHeap.data.length === 2) return maxHeap.data[1]
        if (maxHeap.data.length === 3) {
            return maxHeap.data[1] === maxHeap.data[2] ? 0 : maxHeap.data[1] - maxHeap.data[2]
        }
        const first = maxHeap.data.splice(1, 1)[0]
        const second =maxHeap.data[1]> maxHeap.data[2]?maxHeap.data.splice(1,1)[0]:maxHeap.data.splice(2,1)[0]
        if(first!== second){
            maxHeap.data.push(first-second)
        }

        // 自底向上整理堆
        for(let i=maxHeap.data.length;i>0;i--){
            maxHeap.up(i)
        }
    }
    return 0
};


// 构建最大堆
const Heap = function (k) {
    this.data = new Array(k + 1)
}

Heap.prototype.swap = function (a, b) {
    [this.data[a], this.data[b]] = [this.data[b], this.data[a]]
}

//  从节点下标为 index 的地方,向下整理 -- 一般用于取出后整理
Heap.prototype.down = function (index) {
    if (index >= this.data.length) return // 已经结束
    const left = index * 2
    const right = index * 2 + 1
    let target = index // 初始是父节点
    if (left < this.data.length && this.data[left] > this.data[target]) {
        left = target
    }
    if (right < this.data.length && this.data[right] > this.data[target]) {
        right = target
    }
    // 左右节点有大于父节点的时候,才会替换
    if (index !== target) {
        // 将两个下标对应的值替换,但是下标没有变的
        this.swap(index, target)
        // 整体替换后的子树
        this.down(target)
    }
}

//  一般用于在最右叶子节点插入值,然后进行整理
Heap.prototype.up = function (index) {
    if (index <= 1) return
    const fatherIndex = index >>> 1
    if (this.data[index] > this.data[fatherIndex]) {
        this.swap(index, fatherIndex)
        this.up(fatherIndex)
    }
}