力扣贪心算法

顾名思义,贪心算法或贪心思想采用贪心的策略,保证每次操作都是局部最优的,从而使最
后得到的结果是全局最优的。
举一个最简单的例子:小明和小王喜欢吃苹果,小明可以吃五个,小王可以吃三个。已知苹
果园里有吃不完的苹果,求小明和小王一共最多吃多少个苹果。在这个例子中,我们可以选用的
贪心策略为,每个人吃自己能吃的最多数量的苹果,这在每个人身上都是局部最优的。又因为全
局结果是局部结果的简单求和,且局部结果互不相干,因此局部最优的策略也同样是全局最优的
策略。

有一群孩子和一堆饼干,每个孩子有一个饥饿度,每个饼干都有一个大小。每个孩子只能吃
最多一个饼干,且只有饼干的大小大于孩子的饥饿度时,这个孩子才能吃饱。求解最多有多少孩
子可以吃饱
输入两个数组,分别代表孩子的饥饿度和饼干的大小。输出最多有多少孩子可以吃饱的数
量。

因为饥饿度最小的孩子最容易吃饱,所以我们先考虑这个孩子。为了尽量使得剩下的饼干可
以满足饥饿度更大的孩子,所以我们应该把大于等于这个孩子饥饿度的、且大小最小的饼干给这
个孩子。满足了这个孩子之后,我们采取同样的策略,考虑剩下孩子里饥饿度最小的孩子,直到
没有满足条件的饼干存在。
这里的贪心策略是,给剩余孩子里最小饥饿度的孩子分配最小的能饱腹的饼干。
至于具体实现,因为我们需要获得大小关系,一个便捷的方法就是把孩子和饼干分别排序。
这样我们就可以从饥饿度最小的孩子和大小最小的饼干出发,计算有多少个对子可以满足条件

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;
}
return child;
}

一群孩子站成一排,每一个孩子有自己的评分。现在需要给这些孩子发糖果,规则是如果一
个孩子的评分比自己身旁的一个孩子要高,那么这个孩子就必须得到比身旁孩子更多的糖果;所有孩子至少要有一个糖果。求解最少需要多少个糖果。
输入是一个数组,表示孩子的评分。输出是最少糖果的数量。
你会不会认为存在比较关系的贪心策略一定需要排序或是选择?虽然这一
道题也是运用贪心策略,但我们只需要简单的两次遍历即可:把所有孩子的糖果数初始化为 1;
先从左往右遍历一遍,如果右边孩子的评分比左边的高,则右边孩子的糖果数更新为左边孩子的糖果数加 1;再从右往左遍历一遍,如果左边孩子的评分比右边的高,且左边孩子当前的糖果数不大于右边孩子的糖果数,则左边孩子的糖果数更新为右边孩子的糖果数加 1。通过这两次遍历,分配的糖果就可以满足题目要求了。这里的贪心策略即为,在每次遍历中,只考虑并更新相邻一侧的大小关系。
在样例中,我们初始化糖果分配为 [1,1,1],第一次遍历更新后的结果为 [1,1,2],第二次遍历 更新后的结果为 [2,1,2]。

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] < ratings[i-1]) {
    
    
num[i-1] = max(num[i-1], num[i] + 1);
} }
return accumulate(num.begin(), num.end(), 0); // std::accumulate 可以很方便 地求和 }

给定多个区间,计算让这些区间互不重叠所需要移除区间的最少个数。起止相连不算重叠。
输入是一个数组,数组由多个长度固定为 2 的数组组成,表示区间的开始和结尾。输出一个整数,表示需要移除的区间数量
在这个样例中,我们可以移除区间 [1,3],使得剩余的区间 [[1,2], [2,4]] 互不重叠。
在选择要保留区间时,区间的结尾十分重要:选择的区间结尾越小,余留给其它区间的空间就越大,就越能保留更多的区间。因此,我们采取的贪心策略为,优先保留结尾小且不相交的区间
具体实现方法为,先把区间按照结尾的大小进行增序排序,每次选择结尾最小且和前一个选择的区间不重叠的区间
需要根据实际情况判断按区间开头排序还是按区间结尾排序

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 total = 0, prev = intervals[0][1];
for (int i = 1; i < n; ++i) {
    
    
if (intervals[i][0] < prev) {
    
    
++total;
} else {
    
    
prev = intervals[i][1];
} }
return total;
}

给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false。
输入:flowerbed = [1,0,0,0,1], n = 1
输出:true
贪心,当前位置能种❀,就种❀

class Solution {
    
    
    public boolean canPlaceFlowers(int[] flowerbed, int n) {
    
    
		int ans = 0;
		for (int i = 0; i < flowerbed.length; i++) {
    
    
			//判断当前位置能否种花
			//能种 ❀ 的情况
			if (flowerbed[i] == 0 
					&& (i + 1 == flowerbed.length || flowerbed[i + 1] == 0) 
					&& (i == 0 || flowerbed[i - 1] == 0)) {
    
    
				flowerbed[i] = 1;
				ans++;
			}
		}
		return ans >= n;
	}
}

猜你喜欢

转载自blog.csdn.net/qq_45598881/article/details/121001223