860.柠檬水找零
bool lemonadeChange(vector<int>& bills) {
int five = 0, ten = 0, twenty = 0;
for (int bill: bills) {
if (bill == 5) {
five++;
}
else if (bill == 10) {
if (five > 0) {
five--;
ten++;
}
else return false;
}
else {
if (ten > 0 && five > 0) {
five--;
ten--;
twenty++;
}
else if (five > 2) {
five -= 3;
twenty++;
}
else return false;
}
}
return true;
}
这道题只需要将买的过程分为三种情况,五美元、十美元、二十美元。五美元的情况下,只需要five++;十美元的情况下,需要用五美元找零,如果找不了则返回false; 二十美元的情况下有两种找零方法:找一个十美元和一个五美元或者三个五美元。本题的贪心思想在于收到二十美元的时候优先选择第一种方案找零,这样就不会在要找零十美元的时候先把五美元用完了!
所以局部最优:遇到账单20,优先消耗美元10,完成本次找零。全局最优:完成全部账单的找零。
406.根据身高重建队列
class Solution {
static bool cmp(vector<int> a, vector<int> b) {
if (a[0] == b[0]) return a[1] < b[1];
return a[0] > b[0];
}
public:
vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
sort(people.begin(), people.end(), cmp);
vector<vector<int>> que;
for (int i = 0; i < people.size(); i++) {
que.insert(que.begin() + people[i][1], people[i]);
}
return que;
}
};
这道题也需要从两个维度来考虑问题:一个是身高,另一个是顺序维度。首先呢先将人从大到小排列,如果同样高的就把顺序靠前的排在前面,通过自定义的cmp来实现。
因为已经排好序后,从身高最高的开始选起,所以选取后面的人的时候不会因为前面的身高比较矮而导致排队顺序不确定。也就是说从高到低选取顺序的话一定会满足当前插入的k值,已经排序过的人不会存在比自己矮的!
所以在按照身高从大到小排序后:
局部最优:优先按身高高的people的k来插入。插入操作过后的people满足队列属性
全局最优:最后都做完插入操作,整个队列满足题目队列属性
452. 用最少数量的箭引爆气球
class Solution {
static bool cmp(vector<int> a, vector<int> b) {
return a[0] < b[0];
}
public:
int findMinArrowShots(vector<vector<int>>& points) {
if (points.size() == 0) return 0;
sort(points.begin(), points.end(), cmp);
int count = 1;
int range = points[0][1];
for (int i = 0; i < points.size(); i++) {
if (range < points[i][0]) {
count++;
range = points[i][1];
}
else {
range = min(range, points[i][1]);
}
}
return count;
}
};
这是我的基础思路, 先找一个最右边界,然后在遍历的过程中更新这个最右边界。如果最右边界小于当前遍历到的元素的左边界,说明不能射爆这个气球了,需要再加一根箭同时更新最右边界,如果包含在最右边界内,则需要比较两个右边界,取最小的。
但这个貌似会超时,在数据量很大的情况下会超时。
class Solution {
private:
static bool cmp(const vector<int>& a, const vector<int>& b) {
return a[0] < b[0];
}
public:
int findMinArrowShots(vector<vector<int>>& points) {
if (points.size() == 0) return 0;
sort(points.begin(), points.end(), cmp);
int result = 1; // points 不为空至少需要一支箭
for (int i = 1; i < points.size(); i++) {
if (points[i][0] > points[i - 1][1]) { // 气球i和气球i-1不挨着,注意这里不是>=
result++; // 需要一支箭
}
else { // 气球i和气球i-1挨着
points[i][1] = min(points[i - 1][1], points[i][1]); // 更新重叠气球最小右边界
}
}
return result;
}
};
示例代码,思路相同,只不过是在排序后比较相邻两个边界即可,比较当前范围左边界是否在上一个范围的右边界内。