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