你正在玩一个单人游戏,面前放置着大小分别为 a、b 和 c 的 三堆 石子。
每回合你都要从两个不同的非空堆 中取出一颗石子,并在得分上加 1 分。当存在 两个或更多 的空堆时,游戏停止。
给你三个整数 a 、b 和 c ,返回可以得到的 最大分数 。
示例 1:
输入:a = 2, b = 4, c = 6
输出:6
解释:石子起始状态是 (2, 4, 6) ,最优的一组操作是:
- 从第一和第三堆取,石子状态现在是 (1, 4, 5)
- 从第一和第三堆取,石子状态现在是 (0, 4, 4)
- 从第二和第三堆取,石子状态现在是 (0, 3, 3)
- 从第二和第三堆取,石子状态现在是 (0, 2, 2)
- 从第二和第三堆取,石子状态现在是 (0, 1, 1)
- 从第二和第三堆取,石子状态现在是 (0, 0, 0)
总分:6 分 。
示例 2:
输入:a = 4, b = 4, c = 6
输出:7
解释:石子起始状态是 (4, 4, 6) ,最优的一组操作是:
- 从第一和第二堆取,石子状态现在是 (3, 3, 6)
- 从第一和第三堆取,石子状态现在是 (2, 3, 5)
- 从第一和第三堆取,石子状态现在是 (1, 3, 4)
- 从第一和第三堆取,石子状态现在是 (0, 3, 3)
- 从第二和第三堆取,石子状态现在是 (0, 2, 2)
- 从第二和第三堆取,石子状态现在是 (0, 1, 1)
- 从第二和第三堆取,石子状态现在是 (0, 0, 0)
总分:7 分 。
示例 3:
输入:a = 1, b = 8, c = 8
输出:8
解释:最优的一组操作是连续从第二和第三堆取 8 回合,直到将它们取空。
注意,由于第二和第三堆已经空了,游戏结束,不能继续从第一堆中取石子。
这道题我的想法是每次都从最多的和最少的堆中各取出一个,直到有两个以上的堆数量为0为止。所以我们这里需要用到堆进行排序。
我们可以用大顶堆也可以用小顶堆,我们这里用到的是小顶堆。我们先将三个堆存入小顶堆中,然后取出堆顶,为最小值,再取出堆顶为中间值,最后一个值为最大值,将第一个和最后一个减一,直到最小值为0时,对后两个数进行想减,直到有两个0结束。
/**
* @param {number} a
* @param {number} b
* @param {number} c
* @return {number}
*/
var maximumScore = function (a, b, c) {
let heap = new Heap("small")
heap.push(a)
heap.push(b)
heap.push(c)
let nums = 0
let min = heap.pop()
while (min != 0 || heap.top() != 0) {
nums++
let mid = heap.pop()
let max = heap.pop()
if (min > 0) {
min--, max--;
} else {
mid--, max--;
}
heap.push(min)
heap.push(mid)
heap.push(max)
min = heap.pop()
}
return nums
};
小顶堆代码
class Heap {
constructor(cmp = "large") {
if (cmp == "large") {
this.cmp = this.large;
} else if (cmp == "small") {
this.cmp = this.small
} else {
this.cmp = cmp
}
this.res = [];
this.cnt = 0;
}
push(val) {
this.cnt++;
this.res.push(val)
this.shiftUp(this.cnt - 1)
}
pop() {
this.cnt--;
const res = this.res[0]
const pop = this.res.pop()
if (this.cnt) {
this.res[0] = pop
this.shiftDown(0)
}
return res
}
shiftUp(i) {
if (i === 0) return
const par = this.getParentIndex(i)
if (this.cmp(this.res[par], this.res[i])) {
this.swap(par, i)
this.shiftUp(par)
}
}
shiftDown(i) {
const l = this.getLeftIndex(i)
const r = this.getRightIndex(i)
if (l < this.cnt && this.cmp(this.res[i], this.res[l])) {
this.swap(i, l)
this.shiftDown(l)
}
if (r < this.cnt && this.cmp(this.res[i], this.res[r])) {
this.swap(i, r)
this.shiftDown(r)
}
}
getParentIndex(i) {
return (i - 1) >> 1
}
getLeftIndex(i) {
return i * 2 + 1
}
getRightIndex(i) {
return i * 2 + 2
}
large = (a, b) => a < b
small = (a, b) => a > b;
swap = (i, j) => [this.res[i], this.res[j]] = [this.res[j], this.res[i]];
top = () => this.res[0];
size = () => this.cnt;
isEmpty = () => this.cnt === 0
}