代碼隨想錄算法訓練營|第三十四天|貪心算法理論基礎、455.分发饼干、376. 摆动序列、53. 最大子序和。刷题心得(c++)

文章讲述了作者在学习贪心算法过程中的实践与反思,包括理解贪心算法的本质、解决455分发饼干、376摆动序列和53最大子序和问题的方法,以及遇到的困难和解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

貪心算法理論基礎

讀題

455.分发饼干

自己看到题目的第一想法

376. 摆动序列

自己看到题目的第一想法

看完代码随想录之后的想法

53. 最大子序和

自己看到题目的第一想法

看完代码随想录之后的想法

455.分发饼干 - 實作

思路

Code

376. 擺動序列 - 實作

思路

錯誤思路

正確思路

Code

錯誤代碼

正確代碼

53. 最大子序和 - 實作

思路

Code

總結

自己实现过程中遇到哪些困难

今日收获,记录一下自己的学习时长

相關資料

理论基础

455.分发饼干

376. 摆动序列

53. 最大子序和


貪心算法理論基礎

貪心算法沒有套路,最多就是常識性推倒加上舉反例。

貪心算法的本質是選擇每一階段的局部最優解,經過堆疊達到全局最優

常識性推導:

就像隨想錄所舉的例子,拿鈔票,拿十次讓最後結果的利益最大化

那每次都拿最大的面額的鈔票,到第十次後就可以拿到面額最大的數量

舉反例:

假設要將東西放在包包當中,東西分別有兩個屬性分別是大小與價值

但包包的空間是有限的,假設每次都拿最大的或價值最高的,比如說有一個高價值但大小也高的可能放下去只能放一個,但低價值的比較小累加起來,又比這單一個高價值的大物件有價值。所以在這個時候就無法使用貪心算法,因為無法透過每次拿局部最優的條件,堆疊到全局最優。

所以在貪心算法上,就會需要自己去模擬狀態,如果沒有想到反例,就可以試試看貪心算法,不然就可能需要動態規劃來解決問題。

但算法隨想錄還是有個大略性的贪心算法一般分为如下四步驟:

  • 将问题分解为若干个子问题
  • 找出适合的贪心策略
  • 求解每一个子问题的最优解
  • 将局部最优解堆叠成全局最优解

並且最重要的一點,因為貪心算法的無規律性,如果在刷的過程中不知道該如何解決,直接看題解。

讀題

455.分发饼干

自己看到题目的第一想法

最直觀的想法就是將最適合的餅乾分給適合的小孩,最好是最小的胃口拿到最小剛好適合他胃口的餅乾,那做到這點第一步就是要排序,這樣就可以對應最小的人與餅乾。一開始是用兩個迴圈去跑,並且有分配到餅乾的就標記起來。

之後又優化成用雙指針的想法在一個迴圈中解決這個問題,假設最小的餅乾符合最小的胃口,最小的胃口數值才加加。否則只移動餅乾的陣列。

376. 摆动序列

自己看到题目的第一想法

最初的想法是要可以刪除部分節點達到最大的搖擺子序列,那我的想法是用count紀錄有變化的時候,如果沒有變化則不變,有變化並且符合條件就是一個為正一個為負就加加,但實行這個解法過後,發現有些特殊狀況就會發生問題,假設一開始沒變化,之後有變化就無法解決,或者從頭至尾都沒有變化,也會出現問題,不知道該如何解決

看完代码随想录之后的想法

看完之後,我發現我的作法本質上就是沒有考慮到單調平坡的狀況,所以導致我的解法出現了問題,看完卡哥的講解後,很快就解除我的疑惑了。

53. 最大子序和

自己看到题目的第一想法

原本想先用排序,但發現不能使用,但要怎麼找到最大的子序和我沒有想法。

看完代码随想录之后的想法

連續和 + nums[i]

如果連續和大於result,更新result

假設連續和為正,那繼續計數

假設連續和為負,那在下一個數為初始加加的位置,讓連續和初始為0

所以假設遇到全都是負數的狀況,那result也只會紀錄最大的負數。

455.分发饼干 - 實作

思路

  1. 排序s, g
  2. 設定雙指針
  3. 最小的餅乾假設大於等於最小的胃口量則,最小的胃口量才++,不然只有餅乾會持續++
  4. 假設s或g大於size 則跳出迴圈
  5. return 胃口量的point等同有幾個人被滿足

Code

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(), g.end());
        sort(s.begin(), s.end());
        int g_point = 0;
        int s_point = 0;

        for(g_point = 0, s_point = 0; s_point < s.size(); s_point++) {
            if(s[s_point] >= g[g_point]){
                g_point++;
            }
            if(g_point >= g.size()) break;
        }

        return g_point;
    }
};

376. 擺動序列 - 實作

思路

錯誤思路

  1. 一開始設為1,假設有變化時count++,並且更新max count值
  2. 最後return count

錯誤點:

  1. 是nums.size() < 2 return 1
  2. 沒有考慮到單調平坡的狀況

正確思路

  1. 初始化result = 1, preDiff, curDiff三個值
  2. 遍歷所有節點,當前後有正負數差別時,result++ 並記錄preDiff值,如果波動,preDiff值不用變動
  3. 最後return result

Code

錯誤代碼

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        int count = 0;
        int max_count = 0;
        if(nums.size() <= 2) return 1;

        for(int i = 0; i + 1 < nums.size(); i++) {
            if(i == 0) {
                count = 1;
            } else {
                if(nums[i] - nums[i - 1] > 0 && nums[i + 1] - nums[i] < 0) count++;
                else if (nums[i] - nums[i - 1] < 0 && nums[i + 1] - nums[i] > 0) count++;
                else count = 1;
            }
            if(count > max_count) max_count = count;
        }
        
        return max_count;
    }
};

正確代碼

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        int preDiff = 0;
        int curDiff = 0;
        int result = 1;
        if(nums.size() < 2) return 1;

        for(int i = 0; i + 1 < nums.size(); i++) {
            curDiff =  nums[i + 1] - nums[i];
            if((preDiff >= 0 && curDiff < 0) || (preDiff <= 0 && curDiff > 0)) {
                result++;
                preDiff = curDiff;
            }
        }
        
        return result;
    }
};

 

53. 最大子序和 - 實作

思路

  1. 建立一個results紀錄連續和
  2. for迴圈遍歷所有數組
  3. count += nums[i] → 計算連續和
  4. if count > result, result = count; → 最大的連續和,在全部都是負數的狀況下就是最大的負數
  5. if count < 0 count = 0 —> 連續和為負數則初始為零

Code

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int result = INT_MIN;
        int count = 0;
        for(int i = 0; i < nums.size(); i++) {
            count += nums[i];
            if(count > result) result = count;
            if(count < 0 ) count = 0;
        }
        return result;
    }
};

 

總結

自己实现过程中遇到哪些困难

貪心算法第一天,有點被打回來了,原本回溯解得很開心,但貪心第二題跟第三題就讓我頭疼了

擺動序列的困難點是卡在單調平陂沒有去考慮到,導致無法通過,這個看卡哥的影片很快就理解了

最大子序和則是沒有考慮到暴力姊也沒有想到貪心解,但看完之後又感覺不難,貪心的算法真的很奇妙

今日收获,记录一下自己的学习时长

今天大概學了2hr,基本上都是在想怎麼歸納狀況,實際的code都不難寫,很容易就寫出來了。

相關資料

● 今日学习的文章链接和视频链接

理论基础

https://programmercarl.com/贪心算法理论基础.html

455.分发饼干

https://programmercarl.com/0455.分发饼干.html

376. 摆动序列

https://programmercarl.com/0376.摆动序列.html

53. 最大子序和

https://programmercarl.com/0053.最大子序和.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值