题目
有一堆石头,每块石头的重量都是正整数。
每一回合,从中选出两块 最重的 石头,然后将它们一起粉碎。假设石头的重量分别为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],这就是最后剩下那块石头的重量。
题目分析
我的思路很简单,每次取出数组中前2大的数字,然后计算其差值,如果差值不等于0,那么就将其插入回原数组,直到原数组的元素数量小于等于1。
由于需要频繁查找数组的最大值,我使用了堆,顺便复习一下堆的相关操作。
堆的创建过程如下:
void heapify(int* arr, int size, int i){
if (i >= size) return ;
int c1 = 2 * i + 1;
int c2 = 2 * i + 2;
int max = i;
if (arr[max] < arr[c1]) max = c1;
if (arr[max] < arr[c2]) max = c2;
if (max != i) {
swap(arr, max, i);
heapify(arr, size, max);
}
}
void buildHeap(int* arr, int size){
int last_node = size - 1;
int parent = (last_node - 1) / 2;
for (int i = parent; i >= 0; i++){
heapify(arr, size, i);
}
}
每次调用buildHeap
,就能创建最大堆,取出堆顶元素就是数组的最大值。方便后续操作,我们需要一个删除操作:
int Delete(int* arr, int numSize){
if (numSize == 1) return 0;
for (int i = 0; i < numSize - 1; i++){
arr[i] = arr[i + 1];
}
return --numSize;
}
同时,如果差值不为0,我们需要一个向数组中插入元素的函数:
int attach(int* arr, int numsSize, int k){
arr[numsSize] = k;
return ++numsSize;
}
准备工作完成,我们开始正式解答:
- 如果数组元素个数为0,返回0;
- 如果数组元素个数为1,返回这个元素;
- 如果数组元素个数为2,返回两数差值;
- 如果数组元素个数大于2,迭代:
- 令数组最大值为
a
,数组次大值为b
,两数差值若不为0,将这个差值的绝对值插入数组; - 差值为0,不做操作;
- 重复上述过程,直到数组元素个数为0或1。
- 令数组最大值为
while (stonesSize > 1){
buildHeap(stone, stonesSize);
a = stone[0];
stonesSize = Delete(stone, stonesSize);
buildHeap(stone, stonesSize);
b = stone[0];
stonesSize = Delete(stone, stonesSize);
if (a - b != 0){
attach(stone, stonesSize, abs(a - b));
}
}
完整过程见下文。
题目解答
void swap(int* stones, int i, int j){
int temp = stones[i];
stones[i] = stones[j];
stones[j] = temp;
}
void heapify(int* stones, int stonesSize, int i){
if (i >= stonesSize) return ;
int c1 = 2 * i + 1;
int c2 = 2 * i + 2;
int max = i;
if (c1 < stonesSize && stones[max] < stones[c1]) max = c1;
if (c2 < stonesSize && stones[max] < stones[c2]) max = c2;
if (max != i) {
swap(stones, max, i);
heapify(stones, stonesSize, max);
}
}
void buildHeap(int* arr, int numsSize){
int last_node = numsSize - 1;
int parent = (last_node - 1) / 2;
for (int i = parent; i >= 0; i--){
heapify(arr, numsSize, i);
}
}
int delete_first(int* stones, int stonesSize){
if (stonesSize == 1) return 0;
for (int i = 0; i < stonesSize - 1; i++){
stones[i] = stones[i+1];
}
return --stonesSize;
}
int attach(int* stones, int stonesSize, int k){
stones[stonesSize] = k;
return ++stonesSize;
}
int lastStoneWeight(int* stones, int stonesSize){
if (stonesSize == 0) return 0;
if (stonesSize == 1) return stones[0];
if (stonesSize == 2) return abs(stones[0] - stones[1]);
int a, b;
while (stonesSize > 1){
buildHeap(stones, stonesSize);
a = stones[0];
stonesSize = delete_first(stones, stonesSize);
buildHeap(stones, stonesSize);
b = stones[0];
stonesSize = delete_first(stones, stonesSize);
if (a - b != 0){
stonesSize = attach(stones, stonesSize, abs(a - b));
}else continue;
}
if (stonesSize == 1) return stones[0];
else return 0;
}