贪心算法的学习,简单笔记
1、算法解释
贪心算法/贪心思想:
- 将全局大问题,分解成若干局部小问题
- 使局部小问题为最优
- 全局大问题成为最优
2、分配问题
解题思想——贪心思想
- 对于【孩子】、【饼干】数组,先进行排序
- 从左往右,用饼干【满足】孩子
- 如果满足,当前的孩子和饼干就“移出”
- 如果不满足,当前饼干“移出”,让后面的饼干来
- 返回输出满足孩子的总数量
Java解答——贪心解法
class Solution {
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int child = 0, cookie = 0;
while(child < g.length && cookie < s.length){
if(g[child] <= s[cookie]){ // 孩子能吃饱
child++; // 孩子后移
}
cookie++; // 饼干后移
}
return child;
}
}
解题思想——贪心思想
- 创建两个临时数组,用于存放分数高而多获得的糖果
- 从左往右、从右往左,两次遍历,相邻的比较,更新糖果数量
- 最后将两个临时数组中,每个孩子获得最多的糖果数加和
- 如:
- // Input [1 2 3 2 1]
- // candy_left [0 1 2 0 0]
- // candy_right [0 0 2 1 0]
- // sum = len + 0 + 1 + 2 + 1 + 0 = 9
Java解答——贪心解法
class Solution {
public int candy(int[] ratings) {
int len = ratings.length;
int sum_candy = len; // 每位孩子至少得一颗糖果
int[] candy_left = new int[len];
int[] candy_right = new int[len];
for(int i = 0; i < len - 1; i++){ // for循环,确定两个临时数组的值
if(ratings[i] < ratings[i+1]){ // 右边分数比左边大
candy_left[i+1] = candy_left[i] + 1; // 右边糖果比左边的多1
}
if(ratings[len-1-i]<ratings[len-2-i]){ // 左边分数比右边大
candy_right[len-2-i] = candy_right[len-1-i] + 1;
}
}
for(int i = 0; i < len; i++){ // for循环,用于计算糖果总和
sum_candy+= Math.max(candy_left[i], candy_right[i]);
}
return sum_candy;
}
}
3、区间问题
解题思想——贪心思想
- 首先将各个区间,根据右边界的大小重新排序
- 如果下个区间的左边界比当前区间的右边界大,说明无重叠
- 关键在于对各区间的排序,即对二维数组的排序
Java中的二维数组排序
/*
注意compare 排序中默认升序:
返回 1 == true 代表降序,我想调整顺序
返回 -1 代表升序
*/
Arrays.sort(arrays, new Comparator<int[]>() {
@Override
public int compare(int[] a, int[] b) {
//a[i]里面的i指的是按照每一行的第i列进行排序
// 所以a[0]就是把按照第0列的那个数对所有行进行排序,b[0]既代表其他行的数字
// a[1]就是按照第一列进行排序。
if(a[0]==b[0]){
//如果第 0列的数字相等,那么按第 1列的降序
return b[1]-a[1];
}else{
//如果第 0列的数字不等,那么按第 0列的升序
return a[0]-b[0];
}
}
});
Java解答——贪心解法
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
if (intervals.length == 0) {
return 0;
}
Arrays.sort(intervals, new Comparator<int[]>() { // 对二维数组进行排序
public int compare(int[] interval1, int[] interval2) {
return interval1[1] - interval2[1];
}
});
int n = intervals.length;
int right = intervals[0][1];
int ans = 1;
for (int i = 1; i < n; ++i) {
if (intervals[i][0] >= right) { // 下个区间左边界比当前区间有边界大
++ans; // 无重叠,加一
right = intervals[i][1];
}
}
return n - ans;
}
}
4、练习
解题思想——贪心思想
- 从左至右挨个判断,当前位置是否合适种植
- 若当前位置已经种植,则位置指针加2;若当前位置无,再结合判断临近位置是否没有,以此确定是否种植
Java解答——贪心解法
class Solution {
public boolean canPlaceFlowers(int[] flowerbed, int n) {
// 如果花种完了,或者花床检查完了,都停止遍历
for (int i = 0, len = flowerbed.length; i < len && n > 0;) {
if (flowerbed[i] == 1) {
//即如果,当前i位置已经种植了话,那么下一个可以种花的位置是 i+2
i += 2;
} else if (i == flowerbed.length - 1 || flowerbed[i + 1] == 0) {
//这里很关键
//如果是最后一个位置了,那么肯定能够种植(i==flowerbed.length-1)
//如果不是,则还需要确保 可种花的位置(i+2)紧邻其后的(i+2+1)的位置没有种植(flowerbed[i+1]==0)
//只有这样才可以种植
n--;
//同时找出下一个可以种植的位置
i += 2;
} else {
//这种情况是flowerbed[i+2+1]=1,所以下次循环就从这里重新开始判断其后可种植的位置
i += 3;
}
}
return n <= 0;
}
}
解题思想——贪心思想
- 类似于435题的区间问题
- 先根据各区间右端点排序
- 根据当前区间右端点与下个区间左端点判断是否重叠
- 找到重叠范围的右端点,再继续与下下个区间比较判断
Java解答——贪心解法
class Solution {
public int findMinArrowShots(int[][] points) {
if (points.length == 0) {
return 0;
}
Arrays.sort(points, new Comparator<int[]>() {
public int compare(int[] point1, int[] point2) {
if (point1[1] > point2[1]) {
return 1;
} else if (point1[1] < point2[1]) {
return -1;
} else {
return 0;
}
}
});
int pos = points[0][1];
int ans = 1;
for (int[] balloon: points) {
if (balloon[0] > pos) {
pos = balloon[1];
++ans;
}
}
return ans;
}
}
注
LeetCode435 和 LeetCode452 的二维数组区间排序,
一个是
Arrays.sort(points, new Comparator<int[]>() {
public int compare(int[] point1, int[] point2) {
return point1[1] - point2[1];
}
});
另一个是
Arrays.sort(points, new Comparator<int[]>() {
public int compare(int[] point1, int[] point2) {
if (point1[1] > point2[1]) {
return 1;
} else if (point1[1] < point2[1]) {
return -1;
} else {
return 0;
}
}
});
因为前者无法处理[[-2147483646,-2147483645],[2147483646,2147483647]]用例,会出错
解题思想——贪心思想
- 从左到右遍历字符串,遍历的同时维护当前片段的开始下标 start 和结束下标 end,初始时start=end=0。
- 对于每个访问到的字母 c,得到当前字母的最后一次出现的下标位置 endc ,则当前片段的结束下标一定不会小于endc ,因此令end=max(end,endc)。
- 当访问到下标 end 时,当前片段访问结束,当前片段的下标范围是[start,end],长度为end−start+1,将当前片段的长度添加到返回值,然后令 start=end+1,继续寻找下一个片段。
- 重复上述过程,直到遍历完字符串。
Java解答——贪心解法
class Solution {
public List<Integer> partitionLabels(String S) {
int[] last = new int[26];
int length = S.length();
for (int i = 0; i < length; i++) {
last[S.charAt(i) - 'a'] = i;
}
List<Integer> partition = new ArrayList<Integer>();
int start = 0, end = 0;
for (int i = 0; i < length; i++) {
end = Math.max(end, last[S.charAt(i) - 'a']);
if (i == end) {
partition.add(end - start + 1);
start = end + 1;
}
}
return partition;
}
}
解题思想——贪心思想
- 贪心算法只能用于计算最大利润,计算的过程并不是实际的交易过程
Java解答——贪心解法
class Solution {
public int maxProfit(int[] prices) {
int ans = 0;
int n = prices.length;
for (int i = 1; i < n; ++i) {
ans += Math.max(0, prices[i] - prices[i - 1]);
}
return ans;
}
}
解题思想——贪心思想
- 核心思想:高个子先站好位,矮个子插入到K位置上,前面肯定有K个高个子,矮个子再插到前面也满足K的要求
- 渔(套路):一般这种数对,还涉及排序的,根据第一个元素正向排序,根据第二个元素反向排序,或者根据第一个元素反向排序,根据第二个元素正向排序,往往能够简化解题过程
Java解答——贪心解法
class Solution {
public int[][] reconstructQueue(int[][] people) {
//按数组第一个元素进行降序,按第二个元素进行升序
Arrays.sort(people, new Comparator<int[]>() {
public int compare(int[] person1, int[] person2){
if (person1[0] != person2[0]){
//第一个元素不相等时,第一个元素降序
return person2[0] - person1[0];
}else{
//第一个元素相等时,第二个元素升序
return person1[1] - person2[1];
}
}
});
//新建一个list,用于保存结果集
List<int[]> list = new LinkedList<>();
for (int i = 0; i < people.length; i++) {
if (list.size() > people[i][1]){
//结果集中元素个数大于第i个人前面应有的人数时,将第i个人插入到结果集的 people[i][1]位置
list.add(people[i][1],people[i]);
}else{
//结果集中元素个数小于等于第i个人前面应有的人数时,将第i个人追加到结果集的后面
list.add(list.size(),people[i]);
}
}
//将list转化为数组,然后返回
return list.toArray(new int[list.size()][]);
}
}
解题思想——贪心思想
- 比较临近两个值的大小,若后者大于等于前者则继续循环
- 否则计数加1,并且后者值修改为等于前者
Java解答——贪心解法
class Solution {
public boolean checkPossibility(int[] nums) {
int count = 0;
for (int i = 1; i < nums.length; 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];
}
if (++count > 1) {
return false;
}
}
}
return true;
}
}
这篇博客详细介绍了贪心算法的概念和应用,通过分析LeetCode中的典型题目,如分发饼干、无重叠区间、种花问题等,阐述了解题思路和Java实现。贪心算法将大问题分解为局部最优,以达到全局最优解。
1066

被折叠的 条评论
为什么被折叠?



