根据卡尔的说法,贪心算法没有所谓的套路框架,只有常识。一般来说,贪心算法只要能把测试案例跑通就可以,不需要去证明,贪心不可以,那么就是可以切换到使用动态规划了。
455. 分发饼干
这是一个简单的贪心思想题目,每次满足胃口值最小的孩子,于此同时,我还是运用了双指针的思想。
class Solution {
public int findContentChildren(int[] g, int[] s) {
/**
分析:
简单的贪心思想,小饼干给小胃口值的孩子
*/
int count = 0;
// 对两个数组排好序
Arrays.sort(g);
Arrays.sort(s);
// 定义双指针,特定情况下i指针移动,j指针一直移动
for(int i = 0,j = 0; i < g.length && j < s.length;){
if(s[j] >= g[i]){
// 胃口值得到,满足
i++;
count++;
}
// 切换到下一个饼干
j++;
}
return count;
}
}
1005. K 次取反后最大化的数组和
做完这道题很担心会超时,但是没有超时,很危险的解法,有点像暴力法
class Solution {
public int largestSumAfterKNegations(int[] nums, int k) {
/**
分析:
每次选择一个数的时候,都是选取当前数组中的最小值(可以重复选取),上一轮的操作结果会影响下一轮的选取
*/
// 先排好序
Arrays.sort(nums);
int count = 0;
while(count < k){
nums[0] = -nums[0];
// 重新排序
Arrays.sort(nums);
count++;
}
int sum = 0;
for(int x:nums){
sum += x;
}
return sum;
}
}
860. 柠檬水找零
这是一个生活常识问题应用在leetcode的贪心算法中
class Solution {
public boolean lemonadeChange(int[] bills) {
/**
分析:
常识知道:5元是万金油的,可以用来支付10元账单也可以用来支付20元账单,所以当遇到20元账单的时候,应该优先消费10元+5元的组合,贪心的保留5元
*/
int len = bills.length;
int five = 0, ten = 0;
for(int i = 0; i < len; i++){
// 遇到5元,存起来
if(bills[i] == 5){
five++;
}else if(bills[i] == 10 ){
// 遇到10元,消费5元
if(five <= 0){
return false;
}
five--;
ten++;
}else if(five > 0 && ten > 0){
// 剩下的就是20元的了,优先消费10元+5元组合
five--;
ten--;
}else {
// 最后消费3张5元的
if(five < 3){
return false;
}
five -= 3;
}
}
return true;
}
}
376. 摆动序列
每次都贪心的去寻找峰值???有点像是语文题,其中用了一个技巧就是加入前导数字,解决了前后坡度高度差问题。其实只要想明白了,前后高度差必须要有三个数才可以计算,自然而然就会想到使用前导数字
class Solution {
public int wiggleMaxLength(int[] nums) {
/**
分析:
刚开始看到这道题是很慌的,题目实际上就是要求局部峰值的个数。因为题目谈到了子序列的话题,所以很容易就想到了能不能去删除原始数组的一些数,然后求数组的长度。进入这个误区就很难了额,数组的删除???这个操作麻烦啊,所以还是切换思路,能不能只计算峰值个数,不要去做删除操作。
*/
// 只有一个数字 那必然是摆动的
if(nums.length == 1){
return 1;
}
// 若数字是大于等于2个,如何计算峰值???
// 首先要想到,判断峰值是通过前后的高度差来计算的,也就是说,至少得有3个数!!!
// 前面的高度差和 后面的高度差必须正负号相反,否则就是单调的了
// 那么怎么处理两个数的情况? [2,2] 和[2,5]? 默认给一个前导数2 [2,2,2] 和[2,2,5]
// 初始化
int preDiff = 0;
int curDiff = 0;
// 初始化的个数为1
int count = 1;
for(int i = 1; i < nums.length; i++){
// 当前高度差
curDiff = nums[i] - nums[i-1];
// 这里的preDiff取等号0 是为了判断 初始化条件的
// 如果curDiff=0 是进入不了if语句的
if(curDiff > 0 && preDiff <= 0 || curDiff < 0 && preDiff >= 0){
// 计数
count++;
// 更新
preDiff = curDiff;
}
}
return count;
}
}
55. 跳跃游戏
class Solution {
public boolean canJump(int[] nums) {
/**
分析:
使用贪心策略解题,每次都贪婪的选择下一个可能达到的最大目标.最远能到达某个位置,就一定能到达它前面的任何位置。
*/
// 记录最大位置下标 初始化为0
int maxPos = 0;
for(int i = 0; i < nums.length; i++){
// 遍历数组
// 发现 i 超过了maxPos,说明遇到0了,已经跳不出去了
if(i > maxPos) return false;
// 更新最大下标
maxPos = Math.max(maxPos,i+nums[i]);
}
// 遍历结束 返回true
return true;
}
}