860.柠檬水找零
一开始我以为最后找零就行,有11个测试用例没通过。分析了测试用例,原来必须当场找零。这意味着只要第一位顾客不使用5块钱买柠檬水,那么就当场收摊了。对于10块钱找零只能使用5块钱,对于20块钱找零可以使用10块钱和5块钱或3个5块钱的组合。且优先使用10块钱和5块钱的组合找零20元,因为10块钱只能用于找零20元,而5块钱能用于10块钱和20块钱的找零,使用范围更广。(注:没零钱出来摆什么摊,5块钱一杯柠檬水?抢钱呢)
1.自己版,修改了两次才AC。都是针对有问题的测试用例缝缝补补,代码逻辑不是非常清晰,但总体没什么问题。针对20块的找零有10块就优先使用10块,没有就全都使用5块,因为两种找零方法都需要使用5块所以只需要判断5块钱剩余数量就行。(注:如果有10块钱的情况下找零失败了,说明没有5块钱了,那么全部用5块钱找零的方法也会失败,所以返回false是没问题的)
class Solution {
public:
bool lemonadeChange(vector<int>& bills) {
int five = 0, ten = 0, twenty = 0;
for (int i = 0; i < bills.size(); i++) {
if (bills[i] == 5)
five++;
else if (bills[i] == 10) {
ten++;
five--;
if (five < 0)
return false;
} else {
twenty++;
if (ten > 0) {//优先使用10块找零
ten--;
five--;
} else//没有10块就用5块找零
five -= 3;
if (five < 0)
return false;
}
}
return true;
}
};
2.随想录版,逻辑清晰一点
class Solution {
public:
bool lemonadeChange(vector<int>& bills) {
int five = 0, ten = 0, twenty = 0;
for (int bill : bills) {
// 情况一
if (bill == 5)
five++;
// 情况二
if (bill == 10) {
if (five <= 0)
return false;
ten++;
five--;
}
// 情况三
if (bill == 20) {
// 优先消耗10美元,因为5美元的找零用处更大,能多留着就多留着
if (five > 0 && ten > 0) {
five--;
ten--;
twenty++; // 其实这行代码可以删了,因为记录20已经没有意义了,不会用20来找零
} else if (five >= 3) {
five -= 3;
twenty++; // 同理,这行代码也可以删了
} else
return false;
}
}
return true;
}
};
406.根据身高重建队列
1.按照身高排序之后,优先按身高高的people的k来插入,后序插入节点也不会影响前面已经插入的节点。身高相等的情况下按k升序排列,因为如果身高相等先插入k大的节点,那么后序插入身高相等k小的节点可能会影响之前已经插入的身高相等k大的节点。(vector版)
class Solution {
static bool cmp(const vector<int>& a, const 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>> result;
for (int i = 0; i < people.size(); i++) {
int position = people[i][1];
result.insert(result.begin() + position, people[i]);
}
return result;
}
};
2.list版,效率更高一点。(注:position不能直接用,需要先转换为对应的迭代器类型)
class Solution {
public:
// 身高从大到小排(身高相同k小的站前面)
static bool cmp(const vector<int>& a, const vector<int>& b) {
if (a[0] == b[0])
return a[1] < b[1];
return a[0] > b[0];
}
vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
sort(people.begin(), people.end(), cmp);
list<vector<int>> que; // list底层是链表实现,插入效率比vector高的多
for (int i = 0; i < people.size(); i++) {
int position = people[i][1]; // 插入到下标为position的位置
std::list<vector<int>>::iterator it = que.begin();
while (position--) { // 寻找在插入位置
it++; //将position转换成迭代器类型
}
que.insert(it, people[i]);
}
return vector<vector<int>>(que.begin(), que.end());
}
};
452. 用最少数量的箭引爆气球
1.第一次接触这种题,感觉还是挺抽象的。代码随想录给出的贪心解释是:只射重叠最多的气球,用的弓箭一定最少。我个人觉得这种说法并不容易理解,我认为让每一支箭尽可能射更多的气球这种贪心解释更形象一点。新气球原来的箭能射到,那就不用加箭,只需要调整箭的位置就行。如果射不到那就加一支箭,每次都以重叠部分最小右边界判断新气球能不能射到。
class Solution {
static bool cmp(const vector<int>& a, const vector<int>& b) {
return a[0] < b[0]; //排序比较函数,从小到大
}
public:
int findMinArrowShots(vector<vector<int>>& points) {
int arrow = 1; //数组大小>=1,至少需要一支箭
sort(points.begin(), points.end()); //排序
for (int i = 1; i < points.size(); i++) { //遍历数组从第二个开始
if (points[i][0] > points[i - 1][1]) { //=也算重叠
arrow++; //不重叠多用一支箭
} else { //重叠,更新重叠部分最小右边界
points[i][1] = min(points[i][1], points[i - 1][1]);
}
}
return arrow;
}
};
今日总结:公园综合活动。