网络异常,图片无法展示
|
有一堆石头,每块石头的重量都是正整数。
每一回合,从中选出两块 最重的 石头,然后将它们一起粉碎。假设石头的重量分别为 x
和 y
,且 x <= y
。那么粉碎的可能结果如下:
- 如果
x == y
,那么两块石头都会被完全粉碎; - 如果
x != y
,那么重量为x
的石头将会完全粉碎,而重量为y
的石头新重量为y-x
。
最后,最多只会剩下一块石头。返回此石头的重量。如果没有石头剩下,就返回 0
。
示例:
输入: [2,7,4,1,8,1] 输出: 1 解释: 先选出 7 和 8,得到 1,所以数组转换为 [2,4,1,1,1], 再选出 2 和 4,得到 2,所以数组转换为 [2,1,1,1], 接着是 2 和 1,得到 1,所以数组转换为 [1,1,1], 最后选出 1 和 1,得到 0,最终数组转换为 [1],这就是最后剩下那块石头的重量。 复制代码
提示:
1 <= stones.length <= 30
1 <= stones[i] <= 1000
本题很简单,只需要根据题意要求,每次找出最大的两个值
如果相等,继续取出最大的两个值
如果不等,将它们的差值插入数组,继续取值 直到数组中元素的数量小于两个,此时返回数组中唯一的元素值或者 0
即可
基于以上解题思路,我们有三种方式解题
sort 排序
每次将数组进行升序排序,这样最大的两个值就是数组末尾的两个值
不断取出最大的两个值操作,直到数组中元素数量小于 2
代码如下:
var lastStoneWeight = function(stones) { // 当数组长度大于1的时候取出最大的两个值操作 while(stones.length>1){ // 将数组进行升序排序 stones.sort((a,b) => a-b) // 排序后数组末尾的两个值就是最大的两个值 const num1 = stones.pop(), num2 = stones.pop(); // 如果两数不等,将差值插入数组 if(num1!==num2) stones.push(num1-num2); } return stones[0]||0; }; 复制代码
二分算法
我们还可以只对数组进行一次排序,接下来每次有差值的时候
通过二分算法,在数组中找到第一个大于等于差值的位置进行插入
这样就不用每次都对数组进行排序了
代码如下:
var lastStoneWeight = function(stones) { // 首先对数组进行一次排序 stones.sort((a,b) => a-b); // 当数组长度大于1的时候取出最大的两个值操作 while(stones.length>1){ const num1 = stones.pop(), num2 = stones.pop(); // 如果两数不等,将差值通过二分算法查找合适的位置插入 if(num1!==num2) stones = insert(stones,num1-num2); } // 二分算法插入差值 function insert(arr,num){ if(num<arr[0]) return [num,...arr] else if(num>arr[arr.length-1]) return [...arr,num] // 二分查找第一个大于等于num的位置 let l = 0,r = arr.length-1; while(l<r){ const mid = (l+r)>>1; if(arr[mid]<num) l = mid+1 else r = mid; } // 将num插入 arr.splice(l,0,num); return arr; } return stones[0]||0; }; 复制代码
大顶堆
涉及到维护最值的问题,都可以通过 堆 来解题
本题需要获取的是数组的最大值,所以我们可以通过大顶堆来维护数组中的值,而堆顶元素就是数组中的最大值
每次取出堆顶的两个最大值进行操作 直到堆中的元素数量小于 2
代码如下:
// 大顶堆 class BigHeap{ constructor(){ this.arr = []; this.size = 0; } // 插入操作 push(val){ this.arr.push(val); this.size++; // 插入向上调整 if(this.size>1){ let cur = this.size-1, parent = (cur-1)>>1; while(cur>0&&this.arr[cur]>this.arr[parent]){ [this.arr[parent],this.arr[cur]] = [this.arr[cur],this.arr[parent]] cur = parent,parent = (cur-1)>>1; } } } // 弹出操作 pop(){ if(this.size===0) return false; if(this.size===1){ this.size = 0; return this.arr.pop(); } const res = this.arr[0]; this.arr[0] = this.arr.pop(); this.size--; // 弹出向下调整 let cur = 0, childl = 1,childr = 2; while( (childl<this.size&&this.arr[childl]>this.arr[cur]) || (childr<this.size&&this.arr[childr]>this.arr[cur]) ){ if(childr<this.size&&this.arr[childr]>this.arr[childl]){ [this.arr[cur],this.arr[childr]] = [this.arr[childr],this.arr[cur]] cur = childr; }else{ [this.arr[cur],this.arr[childl]] = [this.arr[childl],this.arr[cur]] cur = childl; } childl = cur*2+1,childr = cur*2+2; } return res; } } var lastStoneWeight = function(stones) { // 创建大顶堆实例 const heap = new BigHeap(); // 将数组中元素插入堆中 for(let i = 0;i<stones.length;i++){ heap.push(stones[i]) } // 当堆中元素数量大于1的时候取出最大的两个值操作 while(heap.size>1){ const num1 = heap.pop(), num2 = heap.pop(); // 如果有差值,将差值插入堆中 if(num1!==num2) heap.push(num1-num2); } return heap.pop()||0; }; 复制代码
至此我们就完成了 leetcode-1046-最后一块石头的重量
如有任何问题或建议,欢迎留言讨论!