day-32 代码随想录算法训练营 贪心part02

122.买卖股票的最佳时机||

思路:计算每一次可得利润

55.跳跃游戏

思路一:覆盖范围内寻找可以到达终点的值

思路二:遍历数组,不断更新最大覆盖范围,从覆盖范围内寻找可以到达终点的值(不同的是需要加条件,当cover==i,也就是到了覆盖范围尽头时,如果nums[i]==0,就无法前进,直接break;

注意:思路一相当于思路二的简化版本,从思路二可以看出直接遍历覆盖范围可以达到明显优化。

class Solution {
public:
    bool canJump(vector& nums) {
        int cover=0;
        if(nums.size()==1) return true;
        for(int i=0;i=nums.size()-1) return true;
            if(cover==i && nums[i]==0) break;//终止条件
        }
        return false;
    }
};

45.跳跃游戏||

思路一:
        从起点开始记录第一个最大覆盖范围lastcover,然后lastcover中不断更新第二个最大覆盖范围cover;
        当第一个最大覆盖范围走到尽头时,对尽头作出终点判断;
        未到达则把第一个最大覆盖范围lastcover更新成第二个最大覆盖范围cover
        此时再进行终点判断

上一次图解

class Solution {
public:
    int jump(vector& nums) {
        int cover=0,precover=0;
        int res=0;
        for(int i=0;i<=precover;i++){
            cover=max(cover,nums[i]+i);
            if(i==precover){//上一个最大覆盖范围走到尽头
                if(precover==nums.size()-1) break;//判断是否走到终点
                else{
                    res++;//还需要跳跃
                    precover=cover;//更新最大覆盖范围
                    if(precover>=nums.size()-1) return res;//判断此时终点是否在最大覆盖范围内
                }
            }
        }
        return res;
    }
};

1005.K次取反后最大化的数组和

思路:先把取反后大的数先取反
形式一:记录正负数的个数,然后判断K和负数的大小
  • 当K<=负数个数,把所有负数取反为正
  • 当K>负数个数,
    • 首先判断是否存在0,存在0就可以对0操作,不改变数组和大小
    • 其次判断K与负数个数的差值的奇偶性,奇数时只需要改变最小的数值,偶数值不需要改变(因为可以在同一个数上多次取反)
class Solution {

public:
    int largestSumAfterKNegations(vector& A, int K) {
        //排序之后,然后判断负数的个数是否小于等于k
        sort(A.begin(),A.end());
        int F=0,Z=0;
        for(int a:A){
            if(a>0) Z++;
            else if(a<0) F++;
        }
        //1.k<=F
        //2.K>F (1)K-F为奇数  (2)K-F为偶数
        int start=0,midF=F;
        if(K<=F){//K<=F时,只需要对负数取反
            while(K--)  A[start++]*=-1;
        }
        else if(K>F){//K>F时,先对负数取反,判断是否存在0,再判断奇偶
            while(midF--) A[start++]*=-1;
            if(A[0]!=0){
                if((K-F)%2!=0){
                    sort(A.begin(),A.end());
                    A[0]*=-1;
                }
            }
        }
        int res=0;
        for(auto it:A)  res+=it;//最后求数组和
        return res;
    }
};
形式二:优化版
class Solution {
static bool cmp(int a, int b) {
    return abs(a) > abs(b);
}
public:
    int largestSumAfterKNegations(vector& A, int K) {
        sort(A.begin(), A.end(), cmp);       // 首先对绝对值进行排序(降序)
        for (int i = 0; i < A.size(); i++) { // 把负数全部取反
            if (A[i] < 0 && K > 0) {
                A[i] *= -1;
                K--;
            }
        }
        if (K % 2 == 1) A[A.size() - 1] *= -1; // 如果k还有,就直接修改最小值
        int result = 0;
        for (int a : A) result += a;        // 数组求和
        return result;
    }
};

134.加油站

思路一:遍历每一个加油站,然后记录当前剩余油量
剩余油量小于0时跳出当前开始
当遍历完成后,如果终止位置已经走了一圈,直接返回开始位置

day-32 代码随想录算法训练营 贪心part02_第1张图片

结果:超出时间限制,注意数据量是10的5次方

思路二:贪心思想
首先记录当前油量,只要当前油量大于等于0,就可以继续遍历
当前油量小于0时,把出发位置放到当前遍历位置 i 的下一位(start=i+1),因为从 i 和 i 之前的位置出发一定无法走完全程;(注意,此时需要更新剩余油量为0,因为已经改变了出发位置为下一位,剩余油量是从0计算的)
遍历结束之后,只要剩余油量大于等于0,说明记录的start是可以走完全程的(因为存在唯一解)
class Solution {
public:
    int canCompleteCircuit(vector& gas, vector& cost) {
        int n=cost.size();
        int totalGas=0;
        int curGas=0;
        int start=0;
        for(int i=0;i=0) return start;//说明总油量够走完全程
        return -1;
    }
};

135.分发糖果

思路:考虑两边孩子和当前位置孩子的评分对比情况
class Solution {
public:
    int candy(vector& ratings) {
        int n=ratings.size();
        vectorcandys(n,1);
        for(int i=1;iratings[i-1])
                candys[i]=candys[i-1]+1;
        }
        for(int i=n-2;i>=0;i--){//考虑左边孩子比右边孩子评分高
            if(ratings[i]>ratings[i+1])
                candys[i]=max(candys[i],candys[i+1]+1);
        }
        int res=0;
        for(auto it:candys)//总和
            res+=it;
        return res;
    }
};

860.柠檬水找零

分析:已知顾客的金额已经固定,所以找的零钱也固定
思路一:面向题目编程
class Solution {
public:
    bool lemonadeChange(vector& bills) {
        unordered_mapbils;
        int n=bills.size();
        for(int i=0;i0 && bils[5]>0){//直接找10 和 5
                        bils[20]++;
                        bils[10]--;
                        bils[5]--;
                    }else if(bils[5]>=3){//找3 张5
                        bils[5]-=3;
                        bils[20]++;
                    }
                    else return false;
                }else{//找5 元
                    if(bils[5]>0){
                        bils[10]++;
                        bils[5]--;
                    }
                    else return false;
                }
            }
        }
        return true;
    }
};

406.根据身高重建队列

思路一:考虑多个维度,数组插入,自定义比较函数
维度一:身高
维度二:前面多少个比自己高或和自己一样高
在根据维度一排序后,然后根据维度二进行插入排序
class Solution {
public:
    static bool cmp(const vector&a,const vector&b){
        if(a[0]==b[0]) return a[1]b[0];//按身高排序
    }
    vector> reconstructQueue(vector>& people) {
        sort(people.begin(),people.end(),cmp);//先根据身高排序
        vector>que;
        for(int i=0;i

你可能感兴趣的:(#,代码随想录算法训练营(19),算法,数据结构)