贪心算法(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個字母,且當前字母最后出現的位置為endiendiendi,end=max(end,endi)end = max(end,endi)end=max(end,endi),當i=endi=endi=end時說明前i+1i+1i+1為一個符合題意的片段;初始化startstartstart為end+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. 最大子序和
代碼
先來個暴力算法
貪心算法
持續更新中
總結
以上是生活随笔為你收集整理的贪心算法(leetcode分类解题,C++代码详细注释)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: loadrunner 11下载及破解
- 下一篇: s3c2440移植MQTT