题目
给定 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 <= 100
0 <= bucket[i], vat[i] <= 10^4
思路
这题有一个比较重要的地方,在于除法的向上取整。
比如 vat = 9 但是 bucket = 4 的时候,还是得装3次。
大佬的思路是,将问题思路转变为,如果我要 i 次装满所有的水缸,我各个位置的水桶都需要多大才行,即(bucket)的大小。
比如当 i = 1 的时候,即为倒一次水即可全部装满。就以实例1来说,那么,一次装满水,vat[0] = 6,bucket[0] = 1,所以相除,需要的bucket大小为6,原本为1,所以需要5次(6 - 1)扩容机会。vat[1] = 8, bucket[1] = 3,所以需要的bucket大小为8,需要5次扩容机会。总扩容次数为10次,装水次数为1,总操作次数为11。
当 i = 2 时,即为倒一次水即可全部装满。那么,两次次装满水,相除得到3,说明需要的bucket大小为3,原本为1,所以需要(3 - 2)扩容机会。第二个桶,相除等于4(8 / 2),所以需要扩容(4 - 3)次,即为1次。总扩容次数为2次,装水次数为2,总操作次数为4。
以此类推当操作次数高到一定程度的时候,扩容次数就慢慢少下来了,通过遍历的方法记录最小值即为答案。
代码
class Solution {
public:
int storeWater(vector<int>& bucket, vector<int>& vat) {
int ans=1e9;
if(*max_element(vat.begin(),vat.end())==0)return 0; // 都为0即返回0
for(int i=1;i<=10000;++i){ // i为装水次数,遍历至10000(题目限制)
int n=vat.size(),sum=i; // sum为操作次数,所以一开始要加上i装水次数
for(int j=0;j<n;++j){
// vat / i 为每个桶需要的大小,减去原来的大小即为扩容次数
// 但是要记住刚刚说到的向上取整的问题,即 9 / 4 应该等于3
// 所以 vat[j] + i - 1 即为向上取整
sum+=max(0,(vat[j]+i-1)/i-bucket[j]);
}
ans=min(ans,sum); // 每次记录操作最小值
}
return ans;
}
};
注意:
为什么 vat[j] + i - 1 / i 是向上取整,就比如举个例子
3 / 3 = 1
int计算默认是向下取整,那么 (3 + 2) / 3 = 1 没有影响结果
而在 2 / 3 = 0,而我们实际想要的结果为 1 , 所以 ( 2 + 2 ) / 3 = 1,那为什么不是 i 而是 i - 1,因为 ( 3 + 3 ) / 3 = 2 已经产生了错误的答案
最后
希望自己算法能力越来越好~