LeetCode 860 柠檬水找零
题目链接:https://leetcode.cn/problems/lemonade-change/
思路:
三种情况:
情况一:给5美元,直接收下
情况二:给10美元,找回5美元
情况三:给20美元:1、给一张十美元和一张五美元;2、给三张五美元
因为五美元适用性更广,所以选择先找回十美元,没有十美元的时候再找五美元。贪心贪在先找回十美元
代码:
使用unordered_map(自写)
class Solution {
public:
bool lemonadeChange(vector<int>& bills) {
unordered_map<int,int>change;
if(bills[0]!=5) return false;
for(int i = 0;i<bills.size();i++)
{
if(bills[i]==5)
change[bills[i]]++;
else if(bills[i]==10)
{
if(change[5]!=0)
{
change[bills[i]]++;
change[5]--;
}
else
return false;
}
else
{
if(change[10]!=0&&change[5]!=0)
{
change[bills[i]]++;
change[10]--;
change[5]--;
}
else if(change[10]==0&&change[5]>=3)
{
change[bills[i]]++;
change[5] -= 3;
}
else
return false;
}
// cout<<change[5]<<" "<<change[10]<<" "<<change[20]<<endl;
}
return true;
}
};
直接使用int记录
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;
}
};
总结
直接模拟题目要求,相对简单。
LeetCode 406 根据身高重建队列
题目链接:https://leetcode.cn/problems/queue-reconstruction-by-height/
思路:
如果题目有多个维度,先尝试确定一个维度,确定下来后再去考虑另外一个维度,不要一起考虑。
如本题,存在身高h和前面比他高的人的数量k,两个维度。
假设先确定k,从小到大排列,会发现最后拍完后k的排列并不符合条件,身高也不符合条件,两个维度哪一个都没确定下来。
所以选择从身高开始排列,身高开始排列也有两种方式,一种从高到低,一种从低到高。最终选择是从高到底排列(身高相同的话,k小的排在前面)
排完后,此时我们可以确定一个维度了,就是身高,前面的节点一定都比本节点高!
所以在按照身高从大到小排序后:
局部最优:优先按身高高的people的k来插入。插入操作过后的people满足队列属性
全局最优:最后都做完插入操作,整个队列满足题目队列属性
插入的过程:
插入[7,0]:[[7,0]]
插入[7,1]:[[7,0],[7,1]]
插入[6,1]:[[7,0],[6,1],[7,1]]
插入[5,0]:[[5,0],[7,0],[6,1],[7,1]]
插入[5,2]:[[5,0],[7,0],[5,2],[6,1],[7,1]]
插入[4,4]:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
代码:
使用数组
class Solution {
public:
vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
vector<vector<int>>queue;
sort(people.begin(),people.end(),cmp);
for(int i = 0;i<people.size();i++)
{
int pos = people[i][1];
queue.insert(queue.begin()+pos,people[i]);
}
return queue;
}
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];
}
};
使用链表
class Solution {
public:
vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
list<vector<int>>queue;
sort(people.begin(),people.end(),cmp);
// 使用链表来进行插入
for(int i = 0;i<people.size();i++)
{
int pos = people[i][1];
std::list<vector<int>>::iterator it = queue.begin();
while(pos--)
it++;
queue.insert(it,people[i]);
}
return vector<vector<int>>(queue.begin(),queue.end());
}
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];
}
};
总结
要学会有多个维度时候要如何去解决问题。
LeetCode 452 用最少数量的箭引爆气球
题目链接:https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/
思路:
贪心:尽可能的让气球重叠在一起
如何判断气球是否重叠在一起?先对气球数组进行排列,按左边界来排。
模拟射爆气球并不需要真的去移除气球。
如果气球重叠了,那么需要将重叠气球中最小的右边界一直更新给当前气球,如果当下一个气球的左边界大于上一个气球的右边界时,说明二者不重叠,此时,弓箭数量+1。
代码:
class Solution {
public:
int findMinArrowShots(vector<vector<int>>& points) {
if(points.size()==0) return 0;
// 按左边界进行排列
sort(points.begin(),points.end(),cmp);
int result = 1; // 记录弓箭数量
// 从1开始记录重叠的气球
for(int i = 1;i<points.size();i++)
{
// 此时气球的左边界如果大于上一个气球的右边界,说明二者不重叠。前一个气球需要一支弓箭去射爆
if(points[i][0]>points[i-1][1])
result++;
else
{
// 将重叠气球的右边界更新为重叠的气球中的最小右边界
points[i][1] = min(points[i][1],points[i-1][1]);
}
}
return result;
}
static bool cmp(const vector<int>&a,const vector<int>&b)
{
return a[0]<b[0];
}
};
总结
思路好理解,代码的具体实现还需要多加努力学习。
今日总结:
加油吧,还有二十五天,时间紧迫。