所用代码 java
什么是贪心?
先找到局部最优,然后每次都是取局部最后,最后得到的就是全局最优。
贪心是没有套路的,只有 局部最优 => 全局最优
分发饼干 LeetCode 455
题目链接:分发饼干 LeetCode 455 - 简单
思路
先遍历孩子的胃口,用大饼干去喂胃口大的孩子 – 逆序
class Solution {
public int findContentChildren(int[] g, int[] s) {
int num = 0;
// 先排序
Arrays.sort(g);
Arrays.sort(s);
int index = s.length - 1;
// 用大饼干喂胃口大的孩子
// 需先遍历胃口
for (int i = g.length - 1; i >= 0; i--){
// 如果index写在if里面就是做完一次比较就会-1
if (index >= 0 && s[index] >= g[i]){
num++;
index--;
}
}
return num;
}
}
总结
起始这题还可以写成用小饼干去喂孩子 – 正序
class Solution {
public int findContentChildren(int[] g, int[] s) {
int num = 0;
// 先排序
Arrays.sort(g);
Arrays.sort(s);
int index = 0;
// 先用小饼干喂
for (int i = 0; i < s.length; i++) {
if (index < g.length && s[i] >= g[index]) {
num++;
index++;
}
}
return num;
}
}
摆动序列 LeetCode 376
题目链接:摆动序列 LeetCode 376 - 中等
思路
无。
局部最优:单调坡里面无元素,只保留顶部和底部的元素,这样就i形成了一个峰
全局最优:局部全是峰,且有最多的峰
主要考虑三点:
- 上下坡(坡顶、坡底)有平坡
- 首尾元素如何处理
- 单调区间的坡有平坡,涉及何时更新坡度
class Solution {
public int wiggleMaxLength(int[] nums) {
if (nums.length == 1) return 1;
// 记录之前的坡度 大于0 小于0 等于0
// 默认前面有一个平坡
int prediff = 0;
// 记录目前的坡度
int curdiff = 0;
// 默认最后一个点是有坡度的
int result = 1;
// 默认最后有坡度就不用遍历到最后
for (int i = 0; i < nums.length - 1; i++) {
curdiff = nums[i+1] - nums[i];
if ((prediff >= 0 && curdiff < 0) ||
(prediff <= 0 && curdiff > 0)){
result++;
// 当有坡度变化的时候才把当前的坡度赋值给前面的坡度
// 否则会出现上面第三种情况,单调且有平坡都会赋值
prediff = curdiff;
}
}
return result;
}
}
总结
只要理解的处理逻辑,本题并不难。我们只要把每次正或负的值定义了一个坡度,每次有坡度变化时就更新坡度,并判断是不是合适的摆动,需注意的是只有一个尾部结点我们也可以看作是一个摆动。
本题还可以使用动态规划的方法来解答,这里先不列出。
最大子数组和 LeetCode 53
题目链接:最大子数组和 LeetCode 53 - 中等
思路
首先想到的是暴力,结果超时了!
class Solution {
public int maxSubArray(int[] nums) {
int max = Integer.MIN_VALUE;
for (int i = 0; i < nums.length; i++) {
int sum = 0;
for (int j = i; j < nums.length; j++) {
sum += nums[j];
max = max > sum ? max : sum;
}
}
return max;
}
}
本题需考虑的是当我们连续和为负数的时候,再去加上下一个数,是要比下一个数更小的,所以就应该从下一个数直接开始。
class Solution {
public int maxSubArray(int[] nums) {
int max = Integer.MIN_VALUE;
int sum = 0;
for (int i = 0; i < nums.length; i++) {
// 若连续和为负数,则加上nums[i]肯定小于nums[i]
// 所以更新起始位置为num[i]
if (sum + nums[i] < nums[i]){
sum = nums[i];
}else {
sum += nums[i];
}
max = max > sum ? max : sum;
}
return max;
}
}
本题代码还可以这样写:
class Solution {
public int maxSubArray(int[] nums) {
int max = Integer.MIN_VALUE;
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
if (sum > max) max = sum;
// 若连续和小于0了,就把连续和和重新赋为零
// 进行下一步的时候再加上
if (sum < 0) sum = 0;
}
return max;
}
}
总结
最大子序和,贪心贪的就在我们每次遇到连续和为负数就不需要了,因为负数再加上一个数肯定时会变小的,我们只要正数的和,正数和才会越加越大。
注意: 不是遇到负数就不要,是连续和为负不要!