每日一题 -- 堆
1046. 最后一块石头的重量
1046. 最后一块石头的重量
分析
- 因为每一次都是敲碎两颗石头,得到差值,然后再进入到序列中,是动态求极值的需求,可以用堆来处理
- 每一次都是求当前最大的两个值,然后求差,如果差不为0,则需要重新插入到堆中,然后再自底向上整理堆
- 这里之所以用遍历所有节点向上整理,是因为每一个差值都会往尾部添加,这个时候需要找出堆中的最大值并放在堆顶,就必须要自底向上递归的去处理。
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]]
}
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)
}
}