Day33
134. 加油站
暴力解法:思路比较简单,遍历所有的节点,看从这个节点开始是否可以完成。需要注意两个点:
1.使用while循环完成每一个点的判断。
2.其中让start+1是因为最后每个点的值只加一次。
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
for(int i =0;i<cost.size();i++){
int curSum=gas[i]-cost[i];
int start=(i+1)%cost.size();
while(curSum>0&& i!=start){
curSum+=gas[start]-cost[start];
start=(start+1)%cost.size();
}
if(curSum>=0 &&i==start) return i;
}
return -1;
}
};
全局最优:首先是加起来所有的燃油找到缺失最多油量的最小值,然后从0开始往前找,找到能够补平这一差值的点。
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int curSum=0;
int min=INT_MAX;
for(int i=0;i<cost.size();i++){
curSum+=gas[i]-cost[i];
if(min>curSum) min=curSum;
}
if(curSum<0) return -1;
if(min>=0) return 0;
for(int i=cost.size()-1;i>=0;i--){
int rest=gas[i]-cost[i];
min+=rest;
if(min>=0) return i;
}
return -1;
}
};
贪心:
局部最优:两个地方:
1.当出现某个点curSum<0之后,为什么中间也不可能出现满足的点?
当s出现<0之后,可以分为s1和s2,如果出现满足的点,则说明s2>0,这样s1<0,根据贪心策略,s1的时候就应该改换起点。
2.为什么在后面的点只要满足到i=cost.size()满足条件, 就可以证明整个循环就满足的?
因为整个流程是>0的,根据贪心策略,前面被分为n个<0的块,只有后面是>0的,所以最后一部分剩余油量一定大于前面所有的空缺值。可以证明之前n个块也都是可以满足的。
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int curSum=0;
int tatalSum=0;
int start=0;
for(int i =0;i<cost.size();i++){
curSum+=gas[i]-cost[i];
tatalSum+= gas[i] - cost[i];
if(curSum<0){
start=i+1;
curSum=0;
}
}
if(tatalSum<0)return -1;
return start;
}
};
135. 分发糖果
贪心策略:每次都只考虑一边,为什么可以?
当左边满足的时候,从右边看,有两种情况:1.>的时候,需要满足左边大,这时候假如数x已经满足左侧排序(左侧,满足的最小值),这是右侧也会有一个y(右侧满足的最小值),比较这两个大小,保证同时满足即可。
而且不会出现左边看candy1<candy2,右边则是candy1>candy2的情况,因为ratings大小是固定的。
class Solution {
public:
int candy(vector<int>& ratings) {
vector<int> candy(ratings.size(),1);
for(int i=1;i<candy.size();i++){
if(ratings[i]>ratings[i-1]){
candy[i]=candy[i-1]+1;
}
}
for(int i=candy.size()-2;i>=0;i--){
if(ratings[i]>ratings[i+1]){
candy[i]=max(candy[i],candy[i+1]+1);
}
}
int result=0;
for(int i=0;i<candy.size();i++){
result+=candy[i];
}
return result;
}
};
860.柠檬水找零
贪心策略:每次都只考虑最近的一个,20的时候先尝试找一张10和一张5.
我的想法是把这些判断写个小函数,但是这个不好分,要按照bills[i]的数来分还是按照five这些的大小来写?
class Solution {
public:
bool lemonadeChange(vector<int>& bills) {
int five=0,ten=0,doll20=0;
for(int i=0;i<bills.size();i++){
if(bills[i]==5){
five++;
}
if(bills[i]==10){
ten++;
if(five<=0){
return false;
}
five--;
}
if(bills[i]==20){
if(five>0&&ten>0){
five--;
ten--;
doll20++;
}
else if(five>=3){
five-=3;
doll20++;
}
else{
return false;
}
}
}
return true;
}
};
406.根据身高重建队列
贪心思路:与分发糖果类似,两边分别处理,先处理其中一层。
本题考虑先处理身高,然后在根据从大到小的顺序插入,这样保证后面的每次插入只需要a【】【1】就可以了。
一种使用vector容器存储,但在这种插入操作中,资源消耗较多。
一种使用链表
class Solution {
public:
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);
vector<vector<int>> que;
for(int i=0;i<people.size();i++){
int position=people[i][1];
que.insert(que.begin()+position,people[i]);
}
return que;
}
};
class Solution {
public:
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;
for(int i=0;i<people.size();i++){
int position=people[i][1];
std:: list<vector<int>> ::iterator it=que.begin();
while(position--){
it++;
}
que.insert(it,people[i]);
}
return vector<vector<int>>(que.begin(),que.end());
}
};