Day33——贪心Ⅲ
目标:
1.leetcode134_加油站
思路:刚开始的思路是维护了一个数组res,其中保存gas[i] - cost-[i];代表当前剩余的油量,如果最终总油量 >= 0,代表肯定能走一圈,主要就是怎么寻找初始位置。
看题解,使用curSum代表当前元素开始的区间和,如果curSum < 0, 那么表示起始位置从当前元素开始肯定会停在这里,所以起始位置一定是从i + 1以后开始。更新位置
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int curSum = 0;
int start = 0;
int totalSum = 0;
for(int i = 0; i < gas.size(); i++) {
curSum += gas[i] - cost[i];
totalSum += gas[i] - cost[i];
if(curSum < 0) {
curSum = 0; // 重置开始位置
start = i + 1;
}
}
if(totalSum < 0) return -1;
return start;
}
2.leetcode135_分发糖果
思路:没思路,看题解
相邻两个孩子评分高的糖果多,分为两个方向考虑,左相邻和右相邻,先考虑右相邻,即 i 从 0 开始,如果 i + 1 大于 i 那么 res[i+1] = res[i] + 1;
此时局部最优:只要右边评分比左边大,右边的孩子就多一个糖果,全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果
局部最优可以推出全局最优。
再考虑左相邻,i = size()-1; 如果 i -1 > i, 那么res[i-1] = res[i] + 1; 但同时需要考虑右相邻的结果,两个都要满足即 res[i-1] = max(res[i]+1, res[i-1]);
int candy(vector<int>& ratings) {
int size = ratings.size();
vector<int> dp(size, 1);
// 处理右相邻
for(int i = 0; i < size - 1; i++) {
if(ratings[i] < rating[i + 1]) {
dp[i+1] = dp[i] + 1;
}
}
// 处理左相邻
for(int i = size -1; i > 0; i--) {
if(ratings[i-1] > ratings[i]) {
// 考虑右相邻
dp[i-1] = max(dp[i-1], dp[i] + 1);
}
}
int sum = 0;
for(int i : dp) sum += i;
return sum;
}
3.leetcode860_柠檬水找零
思路: 简单题我就if else
局部最优:遇到账单20,优先消耗美元10,完成本次找零。全局最优:完成全部账单的找零。
和题解思路一样
bool lemonadeChange(vector<int>& bills) {
int litterNum = 0; // 5美元数量
int bigNum = 0; // 10美元数量
for(int i : bills) {
// cout << i << " " << litterNum << " " << bigNum << endl;;
if(i == 20) {
if(litterNum > 0 && bigNum > 0) {
litterNum--;
bigNum--;
} else if(litterNum > 2) {
litterNum -= 3;
} else return false;
} else if(i == 10) {
if(litterNum > 0) {
bigNum++;
litterNum--;
} else return false;
} else litterNum++;
}
return true;
}
4.leetcode406_根据身高重建队列
思路: