文章目录
贪心算法
分配问题
力扣455 分发饼干
题目描述:
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
示例 1:
输入: g = [1,2,3], s = [1,1]
输出: 1
解释:
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。
示例 2:
输入: g = [1,2], s = [1,2,3]
输出: 2
解释:
你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出2.
提示:
1 <= g.length <= 3 * 10[^4]
0 <= s.length <= 3 * 10[^4]
1 <= g[i], s[j] <= 2[^31] - 1
1.暴力破解法求最值
解题思路
首先我想到就是最简单的暴力破解,下面是我的思路
1.首先先排下序,这会使得比较的时候,都是最小的在前
2.找出每一个孩子能吃的最小饼干,然后将该饼干去除,我这里用的是0表示去除,然后循环遍历就行
分饼干问题肯定涉及贪心了,我这里先只列举我们最初会想到的,也就是无脑遍历
class Solution {
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
//g[] 代表孩子 s代表饼干
int min = Integer.MAX_VALUE;
int count = 0;
/*1.从最小的胃口开始找
* 2.思路:
* 用for循环遍历,看看是否有一个孩子满足,如果满足,count++
* 设置一个最小值,比较最小值,如果有最小值,遍历饼干表,把最小的设置为0
* */
for (int item : g) {
for (int value : s) {
//如果满足,那么count++,饼干设置为0
if (value >= item && value != 0) {
//将满足的都放入记数表
min = Math.min(min, value);
}
}
//找出最小的去除,如果没找到,那么min还是为Integer.MAX_VALUE;如果找到,count++
if (min != Integer.MAX_VALUE) {
count++;
//剔除这个饼干
for (int j = 0; j < s.length; j++) {
if (s[j] == min) {
s[j] = 0;
break;
}
}
}
min = Integer.MAX_VALUE;
}
return count;
}
}
2.采用贪心策略,求最值(齐姐思路)
public static 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;
}
力扣135 分发糖果
贪心策略
题目描述:
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。你需要按照以下要求,帮助老师给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
评分更高的孩子必须比他两侧的邻位孩子获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢?
示例 1:
输入:[1,0,2]
输出:5
解释:你可以分别给这三个孩子分发 2、1、2 颗糖果。
示例 2:
输入:[1,2,2]
输出:4
解释:你可以分别给这三个孩子分发 1、2、1 颗糖果。
第三个孩子只得到 1 颗糖果,这已满足上述两个条件。
解题思路
两次遍历,求分得糖果的最小值
1.先从左向右遍历一遍,如果右边孩子成绩比左边孩子的高,那么右边孩子的糖果更新为左边孩子的糖果数加一
2.从右向左遍历,如果左边孩子成绩数高于右边,并且左边糖果数小于等于右边,左边糖果更新为右边孩子的糖果数加一
至此完毕
代码
class Solution {
public int candy(int[] ratings) {
int length = ratings.length;
int[] count = new int[length];
//初始化糖果数为1
Arrays.fill(count, 1);
//先从左向右遍历一遍,如果右边孩子比左边的高,那么右边孩子的糖果更新为左边孩子的糖果数加一
for (int i = 0; i < length - 1; i++) {
if (ratings[i] < ratings[i + 1]) {
count[i+1]=count[i]+1;
}
}
//从右向左遍历,如果左边数高于右边,并且左边糖果数小于等于右边,左边糖果加一
for (int i = ratings.length - 1; i > 0; i--) {
if (ratings[i] < ratings[i - 1] && count[i - 1] <=count[i] ) {
count[i - 1]=count[i]+1;
}
}
int sum = 0;
for (int c : count
) {
sum += c;
}
return sum;
}
}
区间问题
力扣435 无重叠区间
贪心策略
题目描述:
给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。
注意:
可以认为区间的终点总是大于它的起点。
区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。
示例 1:
输入: [ [1,2], [2,3], [3,4], [1,3] ]
输出: 1
解释: 移除 [1,3] 后,剩下的区间没有重叠。
示例 2:
输入: [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。
示例 3:
输入: [ [1,2], [2,3] ]
输出: 0
解释: 你不需要移除任何区间,因为它们已经是无重叠的了。
解题思路
首先观察题目,要找到需要移除区间的最小数量,那么结尾就很重要了,结尾越小,留给其他区间的空间越大。
1.先进行排序,对每个区间的结尾比较进行递增排序
2.区间比较:先初始化第一个区间,如果第第二个区间的头包含在第一个区间,那么就证明重叠了;如果没有,那么我们就将第一个区间的尾替换成第二个区间的尾;以此类推下去,扩大区间
代码
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, Comparator.comparingInt(o -> o[1]));
//初始化第一个
int pre=intervals[0][1];
int sum=0;
for (int i = 1; i <intervals.length ; i++) {
if (intervals[i][0]<pre){
sum++;
}else {
pre=intervals[i][1];
}
}
return sum;
}
}
练习
力扣 605 种花问题
题目描述
假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false。
示例 1:
输入:flowerbed = [1,0,0,0,1], n = 1
输出:true
示例 2:
输入:flowerbed = [1,0,0,0,1], n = 2
输出:false
提示:
1 <= flowerbed.length <= 2 * 104
flowerbed[i] 为 0 或 1
flowerbed 中不存在相邻的两朵花
0 <= n <= flowerbed.length
解题思路(参考于力扣booooo_)
贪心算法:从左向右遍历花坛,在可以种花的位置就种一朵,能种就种(因为在任一种花时候,不种都不会得到更优解),是一种贪心的思想。
对于当前遍历的位置,这个位置是否能种上花,必须满足以下条件:
-
当前位置 flowerbed[i] = 0flowerbed[i]=0 + 当前这个位置是数组末尾 i == flowerbed.length - 1i==flowerbed.length−1 + 前一个位置上没有种花 flowerbed[i - 1] = 0flowerbed[i−1]=0,此时可以在该位置种花。
-
当前位置 flowerbed[i] = 0flowerbed[i]=0 + 当前这个位置后一个位置没有种花 flowerbed[i + 1] = 0flowerbed[i+1]=0 + 当前这个位置是数组的开头 i == 0i==0,此时可以在该位置种花。
-
当前位置 flowerbed[i] = 0flowerbed[i]=0 + 当前这个位置后一个位置没有种花 flowerbed[i + 1] = 0flowerbed[i+1]=0 + 前一个位置上没有种花 flowerbed[i - 1] = 0flowerbed[i−1]=0,此时可以在该位置种花。
-
当前位置 flowerbed[i] = 0flowerbed[i]=0 并且只有这一个位置,即 i == flowerbed.length - 1iflowerbed.length−1 并且 i == 0i0,此时可以在该位置种花。
注意:要判断当前的位置是否是 flowerbedflowerbed 数组的边界,若是当前位置是数组的开头或结尾,此时只需要看其右边或左边的位置上是否已经种上花了(只需要看连续两个位置即可);若当前位置在数组的中间部分,此时需要看其左右两边位置上是否已经种上了花(需要看连续三个位置)。
代码:
class Solution {
public boolean canPlaceFlowers(int[] flowerbed, int n) {
int m = flowerbed.length;
int count = 0;
for (int i=0;i<m;i++) {
if (flowerbed[i] == 0 && (i == m - 1 || flowerbed[i + 1] == 0) && (i == 0 || flowerbed[i - 1] == 0)) {
flowerbed[i] = 1;
count++;
}
}
return count >= n;
}
}