LeetCode力扣刷题——简单易懂的贪心算法
貪心
一、算法解釋
????????采用貪心的策略,保證每次操作都是局部最優的,從而使最后得到的結果是全局最優的。
????????貪心算法問題需要滿足的條件:
(1)最優子結構:規模較大的問題的解由規模較小的子問題的解組成,規模較大的問題的解只由其中一個規模較小的子問題的解決定;
(2)無后效性:后面階段的求解不會修改前面階段已經計算好的結果;
(3)貪心選擇性質:從局部最優解可以得到全局最優解。
二、經典問題?
1. 分配問題
455. Assign Cookies
455. 分發餅干
????????假設你是一位很棒的家長,想要給你的孩子們一些小餅干。但是,每個孩子最多只能給一塊餅干。對每個孩子 i,都有一個胃口值?g[i],這是能讓孩子們滿足胃口的餅干的最小尺寸;并且每塊餅干 j,都有一個尺寸 s[j]?。如果 s[j]?>= g[i],我們可以將這個餅干 j 分配給孩子 i ,這個孩子會得到滿足。你的目標是盡可能滿足越多數量的孩子,并輸出這個最大數值。
貪心策略:給剩余孩子里最小饑餓度的孩子分配最小的能飽腹的餅干。
int findContentChildren(vector<int>& g, vector<int>& s) {sort(g.begin(),g.end());sort(s.begin(),s.end());int cnt = 0; //記錄得到滿足的孩子的數量int child = 0,cookies = 0;while(child<g.size() && cookies<s.size()){if(g[child] <= s[cookies]){cnt++;child++;}cookies++;}return cnt; }135. Candy??
135. 分發糖果
????????n 個孩子站成一排。給你一個整數數組 ratings 表示每個孩子的評分。你需要按照以下要求,給這些孩子分發糖果:每個孩子至少分配到 1 個糖果。相鄰兩個孩子評分更高的孩子會獲得更多的糖果。請你給每個孩子分發糖果,計算并返回需要準備的最少糖果數目 。
貪心策略:左右各一次遍歷,在每次遍歷中,只考慮并更新相鄰一側的大小關系。
int candy(vector<int>& ratings) {int size = ratings.size();if(size < 2){return size;}vector<int> num(size,1); //初始化每個孩子都分到一個糖果for(int i=1;i<size;i++){if(ratings[i] > ratings[i-1]){num[i] = num[i-1] + 1;}}for(int i=size-1;i>0;i--){if(ratings[i-1] > ratings[i]){num[i-1] = max(num[i]+1,num[i-1]);}} return accumulate(num.begin(),num.end(),0); //accumulate:快速求和函數 }2. 區間問題
435. Non-overlapping Intervals
435. 無重疊區間
????????給定一個區間的集合?intervals?,其中 intervals[i] = [starti, endi]?。返回 需要移除區間的最小數量,使剩余區間互不重疊?。
貪心策略:優先保留結尾小且不相交的區間。
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];}); //按照尾部區間大小排序int removed = 0, prev = intervals[0][1];for (int i = 1; i < n; ++i) {if (intervals[i][0] < prev) {++removed;} else {prev = intervals[i][1]; //更新prev}}return removed; }三、鞏固練習?
605. Can Place Flowers
605. 種花問題
????????假設有一個很長的花壇,一部分地塊種植了花,另一部分卻沒有??墒?#xff0c;花不能種植在相鄰的地塊上,它們會爭奪水源,兩者都會死去。給你一個整數數組??flowerbed 表示花壇,由若干 0 和 1 組成,其中 0 表示沒種植花,1 表示種植了花。另有一個數?n ,能否在不打破種植規則的情況下種入?n?朵花?能則返回 true ,不能則返回 false。
貪心策略:從左向右遍歷花壇,能種就種。可以種花的條件是:
- 自己為空
- 左邊為空 或者 自己是最左邊
- 右邊為空 或者 自己是最右邊
452. Minimum Number of Arrows to Burst Balloons
452. 用最少數量的箭引爆氣球
????????有一些球形氣球貼在一堵用 XY 平面表示的墻面上。墻面上的氣球記錄在整數數組?points?,其中points[i] = [xstart, xend]?表示水平直徑在?xstart?和?xend之間的氣球。你不知道氣球的確切 y 坐標。一支弓箭可以沿著 x 軸從不同點 完全垂直 地射出。在坐標 x 處射出一支箭,若有一個氣球的直徑的開始和結束坐標為 xstart,xend, 且滿足 ?xstart?≤ x ≤ xend,則該氣球會被 引爆???梢陨涑龅墓臄盗?沒有限制 。 弓箭一旦被射出之后,可以無限地前進。給你一個數組 points ,返回引爆所有氣球所必須射出的 最小 弓箭數?。
貪心策略:尋找相交區間,讓更多個氣球重疊。
static bool cmp(const vector<int> &a,const vector<int> &b){return a[1] < b[1]; } int findMinArrowShots(vector<vector<int>>& points) {sort(points.begin(), points.end(), cmp); //按照尾部區間大小排序int num = 1, prev = points[0][1];for (int i = 1; i < points.size(); ++i) {if (points[i][0] > prev) {num++;prev = points[i][1]; //更新prev} }return num; }763. Partition Labels
763. 劃分字母區間
????????字符串?S?由小寫字母組成。我們要把這個字符串劃分為盡可能多的片段,同一字母最多出現在一個片段中。返回一個表示每個字符串片段的長度的列表。
貪心策略:區間每次刷新到最小的但是要全部包含同一字母的位置。
vector<int> partitionLabels(string s) {vector<int> ans;int num[26];int start = 0,end = 0; //劃分一個區間for(int i=0;i<s.size();i++){num[s[i]-'a'] = i; //記錄每個字母最后的位置}for(int i=0;i<s.size();i++){end = max(end,num[s[i]-'a']); //區間最小但要包含全部同一字母if(i == end){ //區間搜索完畢ans.push_back(end-start+1);start = end + 1;}}return ans; }122. Best Time to Buy and Sell Stock II
122. 買賣股票的最佳時機 II
????????給你一個整數數組 prices ,其中?prices[i] 表示某支股票第 i 天的價格。在每一天,你可以決定是否購買和/或出售股票。你在任何時候?最多?只能持有 一股 股票。你也可以先購買,然后在 同一天 出售。返回你能獲得的 最大 利潤?。
貪心策略:在不限制交易次數的情況下,今天價格高于昨天價格即可出售,即求每天的正利潤。
class Solution { public:int maxProfit(vector<int>& prices) {int ans = 0;for(int i=1;i<prices.size();i++){ans += max(0,prices[i]-prices[i-1]);}return ans;} };406. 根據身高重建隊列
406. Queue Reconstruction by Height
????????假設有打亂順序的一群人站成一個隊列,數組 people 表示隊列中一些人的屬性(不一定按順序)。每個 people[i] = [hi, ki] 表示第 i 個人的身高為 hi ,前面 正好 有 ki 個身高大于或等于 hi 的人。
????????請你重新構造并返回輸入數組?people 所表示的隊列。返回的隊列應該格式化為數組 queue ,其中 queue[j] = [hj, kj] 是隊列中第 j 個人的屬性(queue[0] 是排在隊列前面的人)。
貪心策略:先排序,再插隊。
- 首先將數組按身高排序
- 遍歷數組 將 按?k?的值插入到?result 中對應的位置即可
- 返回結果?result 。
(一般這種數對,還涉及排序的,根據第一個元素正向排序,根據第二個元素反向排序,或者根據第一個元素反向排序,根據第二個元素正向排序,往往能夠簡化解題過程。)
class Solution { public:static bool cmp(vector<int> a,vector<int> b){if(a[0] == b[0])return a[1]<b[1];return a[0] > b[0];}vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {sort(people.begin(),people.end(),cmp);vector<vector<int>> result;for(int i=0;i<people.size();i++){int index = people[i][1];result.insert(result.begin() + index,people[i]);}return result;} };665. 非遞減數列
665. Non-decreasing Array
????????給你一個長度為?n?的整數數組?nums?,請你判斷在 最多 改變?1 個元素的情況下,該數組能否變成一個非遞減數列。
????????我們是這樣定義一個非遞減數列的:?對于數組中任意的?i (0 <= i <= n-2),總滿足 nums[i] <= nums[i + 1]。
貪心策略:本題是要維持一個非遞減的數列,所以遇到遞減的情況時(nums[i] > nums[i + 1]),要么將前面的元素縮小,要么將后面的元素放大。問題是維持非遞減的數列,那么我們需要盡可能的讓前面的數字變小,然后尋找可以讓前面數字變小的條件即可,其余的就讓后面數字變大就好了。- 例①:?4, 2, 5
我們可以?把 4 調小到 <= 2? 或者?把 2 調大到 4、5?,使數組有序。
- 例②:?1, 4, 2, 5
我們可以?把 4 調小到 1、2? 或者?把 2 調大到 4、5?,使數組有序。
- 例③:?3, 4, 2, 5
我們必須?把 2 調大到 4、5,才能使數組有序:我們不能把 4 調整為一個?<= 2?的數字,因為 4 前面的元素是 3。
class Solution { public:bool checkPossibility(vector<int>& nums) {int cnt = 0;for(int i=1;i<nums.size();i++){if(nums[i] < nums[i-1]){if(i==1 || nums[i]>=nums[i-2]){nums[i-1] = nums[i];}else{nums[i] = nums[i-1];}cnt++;}}return cnt<=1;} };歡迎大家共同學習和糾正指教
總結
以上是生活随笔為你收集整理的LeetCode力扣刷题——简单易懂的贪心算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python实现支持向量机实例_一个简单
- 下一篇: 原创超简单代码(1.18.50)