Leetcode刷题笔记Day14:贪心Ⅰ

69 阅读3分钟

分发饼干

  • 力扣题目链接
  • 大饼干满足胃口大的,小饼干满足胃口小的,物尽其用!
int findContentChildren(vector<int>& g, vector<int>& s) {
    int j=s.size()-1, cnt=0;
    sort(g.begin(), g.end());
    sort(s.begin(), s.end());
    for(int i=g.size()-1; i>=0; i--){
        // 判断顺序不可弄反
        if(j>=0 && s[j]>=g[i]) {j--; cnt++;}
    }
    return cnt;
}

摆动序列

  • 力扣题目链接
  • 方法1:把符合摆动数列定义的差值记录到vector中,此方式不易出错
int wiggleMaxLength(vector<int>& nums) {
    vector<int> delta(nums.size()-1);
    int cnt=0;
    for(int i=0; i<nums.size()-1; i++){
        delta[cnt]=nums[i+1]-nums[i];
        if(delta[cnt]==0) continue;
        if(cnt>0)
            if(delta[cnt-1]>0 && delta[cnt]>0
               || delta[cnt-1]<0 && delta[cnt]<0)
                continue;
        cnt++;
    }
    return cnt+1;
}
  • 方法2:双指针法优化空间
int wiggleMaxLength(vector<int>& nums) {
    int cnt=0, curDiff=0, preDiff=0;
    // 注意这里要减1,不然越界
    for(int i=0; i<nums.size()-1; i++){
        curDiff=nums[i+1]-nums[i];
        // 出现峰值
        if ((preDiff<=0 && curDiff>0) 
            || (preDiff>=0 && curDiff<0)) {
            cnt++;
            preDiff=curDiff; // 注意,只在摆动变化的时候更新prediff
        }
    }
    return cnt+1;
}

最大子序和

  • 力扣题目链接
  • 方法1:局部最优值不停累加,直到小于0重开,若存在更大的最优,记录下来
int maxSubArray(vector<int>& nums) {
    int maxSum=INT_MIN, tmp=0;
    for(int i=0; i<nums.size(); i++){
        tmp+=nums[i];
        // 位置不能交换,先更新后判断
        if(tmp>maxSum) maxSum=tmp;
        if(tmp<0) tmp=0;
    }
    return maxSum;
}
  • 方法2:动态规划
int maxSubArray(vector<int>& nums) {
    if (nums.size()==0) return 0;
    vector<int> dp(nums.size(), 0); // dp[i]表示包括i之前的最大连续子序列和
    dp[0]=nums[0];
    int result=dp[0];
    for(int i=1; i<nums.size(); i++){
        // 状态转移方程的定义
        dp[i]=max(dp[i-1]+nums[i], nums[i]);
        if(dp[i]>result) result=dp[i];
    }
    return result;
}

买卖股票的最佳时机Ⅱ

int maxProfit(vector<int>& prices) {
    int maxVal=0;
    for(int i=0; i<prices.size()-1; i++)
        if(prices[i+1]-prices[i]>0)
            maxVal+=(prices[i+1]-prices[i]);
    return maxVal;
}
  • 动态规划的方法留到动态规划再说

跳跃游戏

  • 力扣题目链接
  • 终点是否可达,得看每一步的最大覆盖范围
  • cover动态变化作为判断条件是亮点!
bool canJump(vector<int>& nums) {
    int cover=0;
    if(nums.size()==1) return true;
    // 注意,这里不是nums.size()-1哦
    for(int i=0; i<=cover; i++){
        cover=max(nums[i]+i, cover); // 贪心
        if(cover>=nums.size()-1) return true;
    }
    return false;
}

跳跃游戏Ⅱ

int jump(vector<int>& nums) {
    if(nums.size()==1) return 0;
    int cur=0, next=0; // 当前步和下一步最大覆盖范围
    int ans=0;
    for(int i=0; i<nums.size(); i++){
        next=max(nums[i]+i, next);
        if(i==cur){
            cur=next;
            ans++;
            if(next>=nums.size()-1) break;
        }
    }
    return ans;
}
  • 这两道题目都是不需要再回头的,可以再小小优化一下:
int jump(vector<int>& nums) {
    if(nums.size()==1) return 0;
    int cur=0, next=0; // 当前步和下一步最大覆盖范围
    int ans=0;
    // 倒数第二格多一步必到,ans也会++
    for(int i=0; i<nums.size()-1; i++){
        next=max(nums[i]+i, next);
        if(i==cur){
            cur=next;
            ans++;
        }
    }
    return ans;
}

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

  • 按绝对值从大到小排序即可
// 按绝对值从大到小排序,必须是静态函数
static bool cmp(int a, int b){
    return abs(a)>abs(b);
}
int largestSumAfterKNegations(vector<int>& nums, int k) {
    sort(nums.begin(), nums.end(), cmp);
    int sum=0, i=0;
    while(k--){
        if(nums[i]==0) break;
        if(i<nums.size()-1){
            if(nums[i]>0) k++;
            else nums[i]*=-1;
            i++;
        }
        else nums[i]*=-1;
    }
    // 求和
    for(auto num : nums) sum+=num;
    return sum;
}

参考资料

[1] 代码随想录

[2] Leetcode题解