贪心算法理论基础
思路
贪心算法说到底就是一句话,通过找到每一阶段的局部最优,来达到全局最优的效果。
大致思路为:
- 将问题分解为若干个子问题
- 找出适合的贪心策略
- 求解每一个子问题的最优解
- 将局部最优解堆叠成全局最优解
455. Assign Cookies
题目链接:455. Assign Cookies
思路链接:代码随想录贪心算法-分发饼干
思路
在代码随想录中的思路是从右到左(从大到小)遍历,而我给的解法是从左到右(从小到大)遍历,但其实是一样的。
代码随想录的思路是将最大的饼干先喂给最大能够满足的小孩,充分利用饼干尺寸喂饱一个,以达到喂饱所有小孩的全局最优效果;我的思路是将最小的饼干先喂给最小能够满足的小孩,充分利用饼干尺寸喂饱一个,以达到喂饱所有小孩的目的。
做法是将两个数组排序,然后利用双指针,在两个数组上分别定义一个指针,同时开始遍历,如果当前饼干能够满足,那么两个指针同时更新,否则饼干数组指针更新。
Code
class Solution {
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int index1 = 0;
int index2 = 0;
while (index1 != g.length && index2 != s.length) {
if (s[index2] >= g[index1]) {
index1++;
index2++;
} else {
index2++;
}
}
return index1;
}
}
376. Wiggle Subsequence
题目链接:376. Wiggle Subsequence
思路链接:代码随想录贪心算法-摆动序列
思路
不要陷入模拟删除元素的思路中。将数组元素值抽象成山峰图。
通过使序列删除元素后,达到局部峰值的最大值就可以得到答案。
局部最优:通过删除单调坡度上的节点来得到局部峰值
整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列
利用双指针,记录得到当前元素与下一元素之差以及上一元素与当前元素之差。在遍历数组时,如果两个指针的值正负号相异,那么就代表找到了一个局部峰值,更新result。
Code
class Solution {
public int wiggleMaxLength(int[] nums) {
if (nums.length <= 1) {
return nums.length;
}
// 通过当前组之差与前一组之差比较来判断是否是峰值
int currDiff = 0;
int preDiff = 0;
int result = 1;
for (int i = 0; i < nums.length - 1; i++) {
currDiff = nums[i + 1] - nums[i];
if (currDiff > 0 && preDiff <= 0 || currDiff < 0 && preDiff >= 0) {
result++;
preDiff = currDiff;
}
}
return result;
}
}
53. Maximum Subarray
题目链接:53. Maximum Subarray
思路链接:代码随想录贪心算法-最大子序和
思路
暴力解法:两个循环。第一个循环设定起始位置,第二个循环的起始位置是第一个循环遍历到的元素。
贪心算法:
红色的起始位置就是贪心每次取count为正数的时候,开始一个区间的统计。
局部最优:记录最大的连续和
全局最优:最大子序和
预先定义result(整数最小值)和count(0)遍历数组,遍历数组,计算count,如果count大于result,更新result,如果count出现负数,那么重置count为0。
这道题的思路比较难想。
Code
class Solution {
public int maxSubArray(int[] nums) {
int result = Integer.MIN_VALUE;
int count = 0;
for (int i = 0; i < nums.length; i++) {
count += nums[i];
if (count > result) {
result = count;
}
if (count <= 0) {
count = 0;
}
}
return result;
}
}