[算法训练营] 贪心算法专题(二)

简介: [算法训练营] 贪心算法专题(二)

前言

本篇为贪心算法专题,总共5道题目,记录我的解题思路和一些感悟,供大家参考~

376. 摆动序列

链接:376. 摆动序列

解题思路

  • 主要的思路是处理平坡,也就是都是一样的值的情况
  1. 怎么找到峰值?左边比当前节点小,右边比当前节点小,或者反过来
  2. 如果只有两个值怎么办呢?我们需要为他先创建一个值放在左边,它和第一个值相同即可,这样就不会影响结果。
  3. 平坡是峰值:也就是说峰值是连续一样的值,此时只能记录一个峰值

@代码随想录

AC代码

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if(nums.size()<=1)return nums.size();
        int curGap=0;//后一个节点和当前节点的差值
        int preGap=0;//当前节点和前一个节点的差值
        int result=1;
        for(int i=0;i<nums.size()-1;++i){
            curGap = nums[i+1] - nums[i];
            if((preGap>=0&&curGap<0)||(preGap<=0&&curGap>0)){//判断峰值的条件 
                result++;
                preGap = curGap;//只在波动的时候更新前一个差值
            }
        }
        return result;
    }
};

53. 最大子数组和

链接:53. 最大子数组和

解题思路

下面是四种实现方法,这次只讲贪心怎么实现

  1. 题目要求是最长子数组和,所以就要连续还要找最大的
  2. 我们可以这样,先用最小整数作为结果的初始值
  3. 然后,用另一个值count来加
  4. 如果比res大,就更新res
  5. 当这个值为负数时说明这个情况可以舍弃了,从+1的位置继续,同时更新count

AC代码

class Solution {
public:
    //贪心
    int maxSubArray(vector<int>& nums) {
        int res=INT_MIN;
        int count=0;
        for(int i=0;i<nums.size();++i){
            count+=nums[i];
            if(count>res)res=count;
            if(count<=0)count=0;
        }
        return res;
    }
    //滑动窗口
    // int maxSubArray(vector<int>& nums) {
    //     int left = 0, right = 0;
    //     int windowSum = 0, maxSum = INT_MIN;
    //     while(right < nums.size()){
    //         // 扩大窗口并更新窗口内的元素和
    //         windowSum += nums[right];
    //         right++;
    //         // 更新答案
    //         maxSum = windowSum > maxSum ? windowSum : maxSum;
    //         // 判断窗口是否要收缩
    //         while(windowSum < 0) {
    //             // 缩小窗口并更新窗口内的元素和
    //             windowSum -=  nums[left];
    //             left++;
    //         }
    //     }
    //     return maxSum;
    // }
    //动态规划
    // int maxSubArray(vector<int>& nums)
    // {
    //     int n=nums.size();
    //     if(n==0)return 0;
    //     vector<int> dp(n);
    //     dp[0]=nums[0];
    //     for(int i=1;i<n;++i)
    //     {
    //         dp[i]=max(nums[i],nums[i]+dp[i-1]);
    //     }
    //     int ret=INT_MIN;
    //     for(int j=0;j<n;++j)
    //     {
    //         ret=max(ret,dp[j]);
    //     }
    //     return ret;
    // }
    // int maxSubArray(vector<int>& nums)
    // {
    //     int n=nums.size();
    //     if(n==0)return 0;
    //     int dp_0=nums[0];
    //     int dp_1=0,ret=dp_0;
    //     for(int i=1;i<n;++i)
    //     {
    //         dp_1=max(nums[i],nums[i]+dp_0);
    //         dp_0=dp_1;
    //         ret=max(ret,dp_1);
    //     }
    //     return ret;
    // }
    //前缀和
    // int maxSubArray(vector<int>& nums)
    // {
    //     int n=nums.size();
    //     vector <int> presum(n+1);
    //     presum[0]=0;
    //     for(int i=1;i<=n;++i)
    //     {
    //         presum[i]=presum[i-1]+nums[i-1];
    //     }
    //     int minval=INT_MAX;
    //     int ret=INT_MIN;
    //     for(int j=0;j<n;++j)
    //     {   
    //         minval=min(minval,presum[j]);
    //         ret=max(ret,presum[j+1]-minval);
    //     }
    //     return ret;
    // }
};

55. 跳跃游戏

链接:55. 跳跃游戏

解题思路

  • 题目的意思是 从当前位置能否到达最后一个位置 可以超过 但是不能小于
  • 所以可以理解为是在一个位置上它的覆盖范围包含了最后一个位置就算是true
  • 所以只要不断更新新位置范围 到最后找到是否大于最后一个位置的坐标即可

AC代码

class Solution {
public:
    bool canJump(vector<int>& nums) {
        if(nums.size() == 1) return true;
        int cover = 0;
        for(int i = 0;i <= cover;++i){
            cover = max(cover,i+nums[i]);
            if(cover >= nums.size()-1)return true;
        }
        return false;
    }
};

45 跳跃游戏2

链接:45 跳跃游戏2

解题思路

  • 和前面的"跳跃游戏"一样 它也要覆盖最后一个点 不同在于本题要求的是次数 也就是要第几次跳跃才能覆盖最后一个点
  • 当移动下标移动到覆盖范围的最大值还没有覆盖到最后一个点 此时的jmp就要+1
  • 值得注意的是题目说了 生成的测试用例可以到达 nums[n - 1] 就不用考虑其他情况了

AC代码

class Solution {
public:
    int jump(vector<int>& nums) {
        if(nums.size()==1)return 0;
        int curmax=0,nextmax=0,jum=0;;
        for(int i=0;i<nums.size();++i){
            nextmax = max(nextmax,nums[i]+i);
            if(i==curmax){
                curmax = nextmax;
                jum++;
                if(curmax >= nums.size()-1)break;
            }
        } 
        return jum;
    }
};

134. 加油站

链接:134. 加油站

解题思路

参考代码随想录

我的感觉:

  • 贪心的题目没有一种具体的模板,有的只是一种类似技巧性的思想,一般都不会这么想,可能是我写贪心写的太少了,”局部最优推出全局最优“这种思路还不够清晰,继续加油吧

AC代码

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {  
        int curSum=0;
        int totalSum=0;
        int start=0;
        for(int i=0;i<gas.size();++i){ 
            curSum += gas[i] - cost[i];
            totalSum += gas[i] - cost[i];
            if(curSum < 0){//当前累加rest[i]和curSum一旦小于0
                start = i + 1; //起始位置更新为i+1
                curSum = 0;//curSum从0开始
            }
        }
        if(totalSum < 0)return -1;//说明怎么走都不可能跑一圈了
        return start;
    }
};


相关文章
|
7月前
|
算法
算法:贪心算法的原理和基本思路
算法:贪心算法的原理和基本思路
|
6天前
|
算法
算法人生(3):从“贪心算法”看“战胜拖延”(完美主义版)
本文探讨了拖延症的一个常见原因——完美主义,并从贪心算法的角度提供启示。贪心算法通过局部最优决策逼近全局最优解,不保证全局最优,但寻求满意解。完美主义者的拖延源于高标准、过度关注细节、压力和时间管理困难。为解决这个问题,建议接受不完美,设定合理目标,追求良好效果,以及培养时间管理技巧。通过实例说明,调整心态和策略,可以提高工作效率并克服拖延。
|
6天前
|
算法 调度 C语言
算法--贪心算法
贪心算法是每次选择当前最优解,期望达到全局最优,适用于有最优子结构的问题。它不回退,与动态规划不同。适用于分数背包问题,但0-1背包问题可能无法保证最优解。常见应用包括找零、最小生成树、单源最短路径和任务调度。贪心算法步骤包括建模、分问题、求局部最优解及整合。尽管简单,但需谨慎评估是否适用,例如0-1背包问题可能需用动态规划求解。
19 1
|
6天前
|
算法 程序员
贪心算法(被黑心公司强迫写的降薪算法)
贪心算法(被黑心公司强迫写的降薪算法)
|
6天前
|
算法 调度 C++
[数据结构与算法]贪心算法(原理+代码)
[数据结构与算法]贪心算法(原理+代码)
|
6天前
|
人工智能 算法 Java
【算法设计与分析】— —单源最短路径的贪心算法
【算法设计与分析】— —单源最短路径的贪心算法
38 0
|
6天前
|
存储 算法 Java
【算法设计与分析】— —实现最优载的贪心算法
【算法设计与分析】— —实现最优载的贪心算法
34 1
|
6天前
|
存储 算法 Java
【算法设计与分析】— —实现活动安排问题的贪心算法。
【算法设计与分析】— —实现活动安排问题的贪心算法。
57 0
|
6天前
|
算法 调度 Python
Python高级算法——贪心算法(Greedy Algorithm)
Python高级算法——贪心算法(Greedy Algorithm)
238 3
|
6天前
|
存储 算法 程序员
【算法训练-贪心算法 一】买卖股票的最佳时机II
【算法训练-贪心算法 一】买卖股票的最佳时机II
37 0