这个题常规思路就是每次从两个最大的堆中减去一个,直到出现两个空堆,具体实现有多种方法,最近一直在写大顶堆小顶堆,所以找了一个大顶堆的方法,这个就是封装好的堆方法,通过传值可以直接变成大/小顶堆,我这次先写注释,看看能不能写对
方法一 大顶堆
/**
* @param {number} a
* @param {number} b
* @param {number} c
* @return {number}
*/
const defaultCmp = (x, y) => x > y;
const swap = (arr, i, j) => [arr[i], arr[j]] = [arr[j], arr[i]];
class Heap {
constructor(cmp = defaultCmp) {
this.container = [];
this.cmp = cmp;
}
// 从下往上 入堆操作
insert(data) {
const { container, cmp } = this;
container.push(data);
let index = this.size() - 1;
while (index) {
let parent = index - 1 >> 1;
// 如果当前元素不大于当前元素的根元素 就停止
if (!cmp(container[index], container[parent])) {
return;
}
// 否则 交换
swap(container, index, parent);
// 上移动
index = parent;
}
}
// 弹出堆顶元素操作
pop() {
const { container, cmp } = this;
if (!this.size()) {
return null;
}
// 先交换首位节点
swap(container, 0, this.size() - 1);
// 交换完以后 弹出最后一个 即是刚刚交换道末尾的 堆顶元素
const res = container.pop();
// 开始 从上往下比较重新排序 需要堆顶坐标一个变量index,和另外一个标量用来做对比叫做exchange
let index = 0;
let exchange = 2 * index + 1; // 先赋值做节点
let length = this.size();
// 只要不越界就开始循环
while (exchange < length) {
// 判断有右节点不越界 并且右子节点比左节点大 则继续交换
let right = 2 * index + 2;
if (right < length && cmp(container[right], container[exchange])) {
exchange = right;
}
// exhchage 不比 index 大 就终止 break
if (!cmp(container[exchange], container[index])) {
break;
}
// 交换exchange和index
swap(container, exchange, index);
// 重置index和exchange 为下一步做对比
index = exchange;
exchange = 2 * index + 1;
}
// 返回弹出的最大值 即堆顶元素
return res;
}
// 堆的个数
size() {
return this.container.length;
}
}
/**
思路
先构建大顶堆
每次都是从最大的两堆中-1
一直到有2堆为0
*/
var maximumScore = function (a, b, c) {
// 用ABC三个数构建大顶堆
const maxHeap = new Heap()
maxHeap.insert(a)
maxHeap.insert(b)
maxHeap.insert(c)
let ans = 0
// while循环终止条件 有2堆为0 就是size === 1的时候 就中止了
while (maxHeap.size() > 1) {
// 找到最大的两个值 并且-1
let first = maxHeap.pop() - 1
let second = maxHeap.pop() - 1
ans++
// 两个值不为0 继续入堆 开始下一步循环
if (first > 0) maxHeap.insert(first)
if (second > 0) maxHeap.insert(second)
}
return ans
}
方法二 数学计算
var maximumScore = function(a, b, c) {
// 从小到大排序
let arr = [a,b,c].sort((a,b)=> a-b);
// 数学:然而更巧妙的方法是直接判断那两个小的数字之和是否比最大数大,是的话相当于三数之和整除2,实际上每个数都尽可能用掉,最后剩下的就是余数而已,否则直接就是这两个数字之和,因为大数去逐一消掉小数而已
return arr[0] + arr[1] > arr[2] ? parseInt((arr[0] + arr[1] + arr[2])/ 2) : arr[0] + arr[1]
};
其他--错位代码
我用助教的思路改造这个大顶堆,没有改造对 先记录
/*
* @lc app=leetcode.cn id=1753 lang=javascript
*
* [1753] 移除石子的最大得分
*/
// @lc code=start
/**
* @param {number} a
* @param {number} b
* @param {number} c
* @return {number}
*/
const defaultCmp = (x, y) => x > y;
const swap = (arr, i, j) => [arr[i], arr[j]] = [arr[j], arr[i]];
class Heap {
constructor(cmp = defaultCmp) {
this.container = [];
this.cmp = cmp;
}
// 从下往上 入堆操作
insert(data) {
const { container, cmp } = this;
// 入堆
container.push(data);
//取刚入堆的 即最后一个节点 下标
let child = this.size() - 1;
// while循环从下往上排序 判断种植条件网上找不到child的父节点
while (child) {
// 拿到当前节点的父节点下表
// 如果当前元素不大于当前元素的根元素 就停止
// 否则 交换
// 上移动
let parent = child - 1 >> 1;
if (cmp(container[child], container[parent])) {
swap(container, child, parent);
child = parent
} else {
break;
}
}
}
// 弹出堆顶元素操作
pop() {
const { container, cmp } = this;
if (this.size() === 1) {
return container.pop()
}
let res = container[0];
container[0] = container.pop();
/* // 先交换首位节点
swap(container, 0, this.size() - 1)
// 交换完以后 弹出最后一个 即是刚刚交换道末尾的 堆顶元素
let res = container.pop() */
// 开始 从上往下比较重新排序 需要堆顶坐标一个变量index,和另外一个标量用来做对比叫做exchange
// 先赋值做节点
let i = 0;
// 只要不越界就开始循环
// 判断有右节点不越界 并且右子节点比左节点大 则继续交换
// exhchage 不比 index 大 就终止 break
// 交换exchange和index
// 重置index和exchange 为下一步做对比
// 返回弹出的最大值 即堆顶元素
while (i < this.size()) {
let left = 2 * i + 1;
let right = 2 * i + 2;
let exchange = 0;
if (right < this.size()) {
exchange = cmp(container[right], container[left]) ? right : left;
}
if (exchange < this.size() && cmp(container[exchange], container[i])) {
swap(container, exchange, i);
}
i = exchange;
}
return res;
}
// 堆的个数
size() {
return this.container.length;
}
}
/**
思路
先构建大顶堆
每次都是从最大的两堆中-1
一直到有2堆为0
*/
var maximumScore = function (a, b, c) {
// 用ABC三个数构建大顶堆
const maxHeap = new Heap()
maxHeap.insert(a)
maxHeap.insert(b)
maxHeap.insert(c)
let ans = 0
// while循环终止条件 有2堆为0 就是size === 1的时候 就中止了
while (maxHeap.size() > 1) {
// 找到最大的两个值 并且-1
let first = maxHeap.pop() - 1
let second = maxHeap.pop() - 1
ans++
// 两个值不为0 继续入堆 开始下一步循环
if (first > 0) maxHeap.insert(first)
if (second > 0) maxHeap.insert(second)
}
return ans
}
// @lc code=end