【算法训练营Day23】贪心算法part1
文章目录
- 理论基础
- 分发饼干
- 摆动序列
- 最大子数组和
理论基础
贪心的本质是一种思想:选择每一阶段的局部最优,从而达到全局最优。
贪心的使用场景:一道题目要证明能使用贪心算法那就要涉及到庞杂的数学证明。一般不会这么去实践。在实际刷题或者面试的时候,手动模拟一下感觉可以局部最优推出整体最优,而且想不到明显反例,那么就试一试贪心。
贪心的解题套路与模板:不像二叉树、回溯算法没有那么具体的解题套路和模板。
分发饼干
题目链接:455. 分发饼干
解题逻辑:
本题要达到的局部的最优就是让每个孩子得到最小尺寸且满足胃口的饼干,这样从全局来说能满足更多的孩子。
解题代码如下:
class Solution {public int findContentChildren(int[] g, int[] s) {Arrays.sort(s);int count = 0;int[] record = new int[s.length];for(int i = 0;i < g.length;i++) {int need = g[i];for(int j = 0;j <s.length;j++) {int support = s[j];if(support >= need && record[j] == 0) {count++;record[j] = 1;break;}}}return count;}
}
这种算法就是先将饼干尺寸排个序,使用嵌套for循环根据孩子的胃口去匹配最小符合要求的饼干。这个方法的效率不高,可以使用双指针法进行升级:
class Solution {public int findContentChildren(int[] g, int[] s) {Arrays.sort(s);Arrays.sort(g);int count = 0;int need = 0;int support = 0;while(need < g.length && support < s.length) {if(g[need] <= s[support]) {count++;need++;support++;continue;}support++;}return count;}
}
摆动序列
题目链接:376. 摆动序列
首先我们约定:
- nums[i] - nums[i - 1] > 0 表示上升
- nums[i] - nums[i - 1] < 0 表示下降
- nums[i] - nums[i - 1] = 0 表示平坡
贪心思想:我们要想摆动序列尽量地长,那么就要交错的选择上升以及下坡。
我们首先可以定义两个变量:
- up:表示末尾向上摆动的序列最长长度,初始值为1
- down:表示末尾向下摆动的序列最长长度,初始值为1
从索引1开始遍历数组,如果上升则up = down + 1,如果是下降的则down = up + 1。平坡不影响两种摆动序列的最长长度。最后up 和 down 中较大的那个就为摆动序列的最长子序列的长度
代码如下:
class Solution {public int wiggleMaxLength(int[] nums) {if(nums.length < 2) return 1; int up = 1;int down = 1;for(int i = 1; i < nums.length; i++){up = nums[i] > nums[i - 1] ? down + 1 : up;down = nums[i] < nums[i - 1] ? up + 1 : down;}return Math.max(up, down);}
}
最大子数组和
题目链接:53. 最大子数组和
方法1:暴力
双层for循环嵌套
方法2:回溯算法
获取该数组的所有组合,然后和最大的就行。不过这种暴力解法很耗时,在leetcode中ac不了
方法3:贪心算法
这一题如果使用贪心算法,那么局部最优就是:保证当前的连续和为正数,这样才能对后续添加的元素产生增加作用,如果当前和为负数,那么就从下一个元素重新计算连续和。一次可以推出全局最优。
代码如下:
class Solution {public int maxSubArray(int[] nums) {int sum = 0;int maxSum = Integer.MIN_VALUE;for(int i = 0;i < nums.length;i++){if(sum < 0) sum = 0;sum += nums[i];if(sum > maxSum) maxSum = sum;}return maxSum;}
}