日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

贪心算法(leetcode分类解题,C++代码详细注释)

發布時間:2023/12/10 c/c++ 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 贪心算法(leetcode分类解题,C++代码详细注释) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

貪心算法

  • 前言
  • 455.分發餅干
  • 135.分發糖果
  • 435.無重疊區間
  • 605.種花問題
  • 452.用最小數量的箭引爆氣球
  • 763.劃分字母區間
  • 122. 買賣股票的最佳時機 II
  • 376. 擺動序列
  • 53. 最大子序和

前言

貪心算法或貪心思想采用貪心的策略,保證每次操作都是局部最優的,從而使最后得到的結果是全局最優的。

455.分發餅干


題解
因為饑餓度最小的孩子最容易吃飽,所以我們先考慮這個孩子。為了盡量使得剩下的餅干可以滿足饑餓度更大的孩子,所以我們應該把大于等于這個孩子饑餓度的、且大小最小的餅干給這個孩子。滿足了這個孩子之后,我們同樣的策略,考慮剩下孩子里饑餓度最小的孩子,直到沒有滿足條件的餅干存在。

簡而言之,這里的貪心策略是,給剩余孩子里最小饑餓度的孩子分配最小的能飽腹的餅干。

至于具體實現,因為我們需要獲得大小關系,一個便捷的方法就是把孩子和餅干分別排序。

這樣我們就可以從饑餓度最小的孩子和大小最小的餅干出發,計算有多少個對子可以滿足條件。


注意: 對數組或字符串排序是常見的操作,方便之后的大小比較。

注意: 在之后的講解中,若我們談論的是對連續空間的變量進行操作,我們并不會明確區分數組和字符串,因為他們本質上都是在連續空間上的有序變量集合。一個字符串“abc”可以被看作一個數組 [‘a’,‘b’,‘c’]。

C++代碼

class Solution { public:int findContentChildren(vector<int>& children, vector<int>& cookies) {sort(children.begin(), children.end());sort(cookies.begin(), cookies.end());int child = 0, cookie = 0;//初始化兩個指針,一個指向第一個小孩,另一個指向第一個餅干。while (child < children.size() && cookie < cookies.size()) //指針在正常范圍內,運行{if (children[child] <= cookies[cookie]) ++child;//如果第cookie個cookies 比第child個childern大,說明第child個childern可以被滿足,于是小孩與餅干指針同時向后移動。++cookie;//如果餅干不能滿足小孩,那么餅干指針向下移}//直到某個指針超范圍,返回滿足的小孩數return child;} };

135.分發糖果


解題
雖然這道題leetcode規定為困難,但我覺得這道題是貪心算法中簡單的一種。
首先,我們需要初始化一個全為1的數組,從右向左遍歷數組,如果左邊比右邊大,那么左邊就在右邊基礎上加一;再從左向右遍歷數組,如果右邊比左邊大,右邊就在左邊的基礎上加一;
這里的貪心策略就是只考慮相鄰兩位的關系

代碼

class Solution { public:int candy(vector<int>& ratings) {int size = ratings.size();if(size<2){return size;}//如果只有一個,那么就直接返回1就可以vector<int> nums(size,1);//初始化全為一的數組for(int i = 1;i<size;++i)//從左向右掃描,如果右邊比左邊大,那么右邊在左邊的基礎上加一{if(ratings[i]>ratings[i-1]){nums[i]=nums[i-1]+1;}}for(int i = size-1;i>0;--i)//從右邊向左邊掃描,如果右邊比左邊大,再比較一下是本身大,還是右邊加一大。{if(ratings[i-1]>ratings[i]){nums[i-1]= max(nums[i-1],nums[i]+1);}}return accumulate(nums.begin(), nums.end(), 0);//返回數組中所有元素的和} };

435.無重疊區間

解題
在選擇要保留區間時,我們應該注意區間的結尾,我們選擇的區間結尾越小,那么我們保留下來的區間就越多,因此我們采取的貪心策略為,優先保留結尾小且不相交的區間。

那么如何實現呢?
首先,先把區間按照結尾的大小排序;然后,每次選取結尾最小的且和前一個選擇的區間不重疊的區間。這就需要用到C++ 的lambda,并結合std::sort()函數進行自定義排序

代碼

class Solution { public:int eraseOverlapIntervals(vector<vector<int>>& intervals) {if(intervals.empty()){return 0;}int n = intervals.size();sort(intervals.begin(),intervals.end(),[](vector<int> a,vector<int> b){return a[1] < b[1];});//C++ lambda函數自定義排序,如果看不懂,請移步C++基礎int abandon = 0,prev = intervals[0][1];//初始化prev指針指向第一組第二個數for(int i = 1;i<n;++i){if(intervals[i][0]<prev)//如果后一組第一個數小于前一組第二個數,說明區間有重復,需要舍棄后一組(原因建見題解),所以abandon加一。{++abandon;}else{prev = intervals[i][1];}//如果后一組第一個數大于這一組第二個數,那么prev指向這一組。}return abandon;} };

605.種花問題

題解
這道題的貪心策略就是能種就種。

代碼

class Solution { public:bool canPlaceFlowers(vector<int>& flowerbed, int n) {int ans =0;for(int i = 0 ;i <flowerbed.size();++i)//遍歷{if(flowerbed[i]==0 && (i+1 == flowerbed.size() || flowerbed[i+1] == 0)&& (i == 0 || flowerbed[i-1] == 0))//判讀是否能種,能種就種。首先當前位置是0;其次,當前位置是末尾或者下一個位置是0;然后,當前位置是首位,或者前一個位置是0。這樣的位置你就可以歡樂的種花花了。{flowerbed[i]= 1;ans += 1;//種花位置加1}}return ans >= n;} };

452.用最小數量的箭引爆氣球


題解
這道題看著挺長,其實很簡單

注意這是按末尾坐標排序的
排序后如何放箭就顯而易見了,第一把箭放在黃色框末尾,第二把箭放在藍色框框末尾

代碼

class Solution { public:int findMinArrowShots(vector<vector<int>>& points) {if (points.empty()) {return 0;}sort(points.begin(), points.end(), [](const vector<int>& u, const vector<int>& v) {return u[1] < v[1];});//通過C++ lambda函數對每組坐標以末尾進行排序int pos = points[0][1];//初始化第一把箭的位置為第一個氣球右坐標。int ans = 1;//如果有氣球,一定會使用一支箭。for (const vector<int>& balloon: points) {if (balloon[0] > pos)//如果某個氣球的左坐標大于箭的位置,說明它已經超出了第一支箭所能射擊的范圍,所以箭數加一 ,并將這個氣球的右坐標設置為喜下一支箭的初始位置。{pos = balloon[1];++ans;}}return ans;//返回箭數} };

763.劃分字母區間


題解
遍歷字符串,通過哈希表或者數組記錄每個字母最后一次出現的位置;再遍歷字符串,設遍歷第iii個字母,且當前字母最后出現的位置為endiendiendiend=max(end,endi)end = max(end,endi)end=max(end,endi),當i=endi=endi=end時說明前i+1i+1i+1為一個符合題意的片段;初始化startstartstartend+1end+1end+1,重復上述操作
如果理解不了,可以畫畫,就明白了。

代碼

class Solution { public:vector<int> partitionLabels(string S) {int last[26];//此數組將用于保存每個字母最后出現的位置int length =S.size();for(int i =0;i<length;++i){last[S[i]-'a'] = i;//記錄每個字母最后出現的位置}vector<int> partition;int start = 0,end =0;for(int i =0;i<length;++i){end = max(end,last[S[i]-'a']);//尋找邊界if(i == end ){partition.push_back(end-start+1);start = end +1;}}return partition;} };

122. 買賣股票的最佳時機 II


題解
貪心策略:漲了就賣。至于為什么第二天漲了就賣出呢,因為在持續增長的情況下接連賣出和漲到最高點賣出獲利是一樣的,所以只要第二天漲了就賣出。

代碼

//太簡單了,實在是沒什么好注釋的!!!! class Solution { public:int maxProfit(vector<int>& prices) {int res =0;for(int i =1; i < prices.size();++i){if(prices[i]>prices[i-1]){res += prices[i] -prices[i-1];}}return res;} };

376. 擺動序列

題解

代碼

class Solution { public:int wiggleMaxLength(vector<int>& nums) {if(nums.size()<2) return nums.size();int cur =0;int pre =0;int result =1;for(int i =1;i<nums.size();++i){cur = nums[i]-nums[i-1];if((pre >= 0 && cur <0) || (pre<=0 && cur>0)){++result;pre =cur;}}return result;} };

53. 最大子序和

代碼
先來個暴力算法

class Solution { public:int maxSubArray(vector<int>& nums) {int result = INT32_MIN;int count = 0;for (int i = 0; i < nums.size(); i++) { // 設置起始位置count = 0;for (int j = i; j < nums.size(); j++) { // 每次從起始位置i開始遍歷尋找最大值count += nums[j];result = count > result ? count : result;}}return result;} };

貪心算法

持續更新中

總結

以上是生活随笔為你收集整理的贪心算法(leetcode分类解题,C++代码详细注释)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。