给定 N 个无限容量且初始均空的水缸,每个水缸配有一个水桶用来打水,第 i 个水缸配备的水桶容量记作 bucket[i]。小扣有以下两种操作:
- 升级水桶:选择任意一个水桶,使其容量增加为
bucket[i]+1 - 蓄水:将全部水桶接满水,倒入各自对应的水缸
每个水缸对应最低蓄水量记作 vat[i],返回小扣至少需要多少次操作可以完成所有水缸蓄水要求。
注意:实际蓄水量 达到或超过 最低蓄水量,即完成蓄水要求。
示例 1:
输入:
bucket = [1,3], vat = [6,8]输出:
4解释: 第 1 次操作升级 bucket[0]; 第 2 ~ 4 次操作均选择蓄水,即可完成蓄水要求。
示例 2:
输入:
bucket = [9,0,1], vat = [0,2,2]输出:
3解释: 第 1 次操作均选择升级 bucket[1] 第 2~3 次操作选择蓄水,即可完成蓄水要求。
提示:
1 <= bucket.length == vat.length <= 1000 <= bucket[i], vat[i] <= 10^4
题解:
/**
* @param {number[]} bucket
* @param {number[]} vat
* @return {number}
*/
// 方法一:
var storeWater = function (bucket, vat) {
let max = Math.max(...vat);
if (max === 0) {
return 0;
}
// 求蓄水次数为op时的总操作数
// 打水op次 对应 upgrades 桶需要升级次数
let ops = (op) => {
let upgrades = 0;
for (let i = 0; i < vat.length; i++) {
// 桶需要升级的次数
upgrades += Math.max(0, Math.ceil(vat[i] / op) - bucket[i]);
}
return upgrades + op;
}
// 遍历蓄水次数,求总操作次数的最小值
// 当op大于minOp时,ops(op)必定大于minOp,故可用minOp作为循环结束点
let minOp = Infinity;
let op = 0;
// 依次遍历 op => 打水次数
while (op < minOp) {
op++;
minOp = Math.min(minOp, ops(op));
}
return minOp;
};
// 方法二:
var storeWater = function (bucket, vat) {
// 去掉水缸容量为0的情况
if (vat.includes(0)) {
bucket.splice(vat.indexOf(0), 1)
vat.splice(vat.indexOf(0), 1)
}
// 计算 每一个水桶完成蓄水的次数
let arr = bucket.map((v, i) => {
if (bucket[i] === 0) {
return vat[i] + 1
} else {
return Math.ceil(vat[i] / bucket[i]);
}
});
// 当数组长度不存在时,说明水缸容量都为0
if (!arr.length) return 0;
// 找出数组arr中最大次数 , 设立count为升级桶的次数
let max = Math.max(...arr), count = 0;
let maxIndex = arr.indexOf(max);
// 假设最小次数
let minCount = max + count;
// 当升级次数小于max
while (count < max) {
// 升级水桶
bucket[maxIndex]++;
count++;
arr[maxIndex] = Math.ceil(vat[maxIndex] / bucket[maxIndex]);
max = Math.max(...arr);
minCount = Math.min(max + count, minCount)
maxIndex = arr.indexOf(max);
}
return minCount
};