js(72)~[1753] 移除石子的最大得分

127 阅读3分钟

本题力扣传送门

这个题常规思路就是每次从两个最大的堆中减去一个,直到出现两个空堆,具体实现有多种方法,最近一直在写大顶堆小顶堆,所以找了一个大顶堆的方法,这个就是封装好的堆方法,通过传值可以直接变成大/小顶堆,我这次先写注释,看看能不能写对

方法一 大顶堆

/**
 * @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