LeetCode-2335. 装满杯子需要的最短总时长【贪心,数学】
题目描述:
现有一台饮水机,可以制备冷水、温水和热水。每秒钟,可以装满 2 杯 不同 类型的水或者 1 杯任意类型的水。
给你一个下标从 0 开始、长度为 3 的整数数组 amount ,其中 amount[0]、amount[1] 和 amount[2] 分别表示需要装满冷水、温水和热水的杯子数量。返回装满所有杯子所需的 最少 秒数。
示例 1:
输入:amount = [1,4,2]
输出:4
解释:下面给出一种方案:
第 1 秒:装满一杯冷水和一杯温水。
第 2 秒:装满一杯温水和一杯热水。
第 3 秒:装满一杯温水和一杯热水。
第 4 秒:装满一杯温水。
可以证明最少需要 4 秒才能装满所有杯子。
示例 2:
输入:amount = [5,4,4]
输出:7
解释:下面给出一种方案:
第 1 秒:装满一杯冷水和一杯热水。
第 2 秒:装满一杯冷水和一杯温水。
第 3 秒:装满一杯冷水和一杯温水。
第 4 秒:装满一杯温水和一杯热水。
第 5 秒:装满一杯冷水和一杯热水。
第 6 秒:装满一杯冷水和一杯温水。
第 7 秒:装满一杯热水。
示例 3:
输入:amount = [5,0,0]
输出:5
解释:每秒装满一杯冷水。
提示:
amount.length == 3
0 <= amount[i] <= 100
解题思路一:其实像一道数学题目。假设三个杯子x<=y<=z先分两种情况。第一种:x+y<=z,答案直接是最大的z。第二种:x+y>z。先将x与y互相匹配t次直到x+y<=z。那么t=(x+y-z)/2向上取整,即t>=1。取消向上取整则t=(x+y-z+1)/2,然后变回第一种情况,总的时长为t+z=(x+y+z+1)/2。
class Solution {
public:
int fillCups(vector<int>& amount) {
sort(amount.begin(),amount.end());
if(amount[2]>=amount[0]+amount[1]) return amount[2];
return (amount[0]+amount[1]+amount[2]+1)/2;
}
};
时间复杂度:O(1)
空间复杂度:O(1)
解题思路二:优化,一行代码!
直接返回四个数中最大的那一个即可。
class Solution {
public:
int fillCups(vector<int>& a) {
return max({a[0], a[1], a[2], (a[0] + a[1] + a[2]+1)/2});
}
};
时间复杂度:O(1)
空间复杂度:O(1)
解题思路三:比较费时但好理解的,排序然后大的两个数减1,记次数。
class Solution {
public:
int fillCups(vector<int>& a) {
int s=0;
while(a[0]||a[1]||a[2]){
sort(a.begin(),a.end());
s++;
if(a[1]) a[1]--;
if(a[2]) a[2]--;
}
return s;
}
};