1. 贪心算法
贪心算法的思路是找到局部最优解,然后求出全局最优解有固定模板。
2. 分发饼干
力扣
要先遍历需求g[i],让其自减,如果满足不了就比较下一个。
有两种思路,都需要先对两个数组进行排序。一种思路是从后往前遍历,让大尺寸的饼干先满足大胃口的,如果满足不了就到下一个,如果可以满足就将遍历尺寸的Index减一。
代码实现
class Solution {
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int count = 0;
int end = s.length - 1;
for(int i = g.length - 1; i >= 0; i--){
if(end >= 0 && s[end] >= g[i]){
count++;
end--;
}
}
return count;
}
}
另一种思路是从前向后遍历,在力扣上该方法用时较少。这个就要先遍历尺寸,如果该尺寸满足不了当前需求就向后找直到满足,然后再处理下一个需求。
class Solution {
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int count = 0;
int start = 0;
for(int i = 0; i < s.length; i++){
if(start < g.length && s[i] >= g[start]){
count++;
start++;
}
}
return count;
}
}
3. 摆动序列
首先要理解本题:子序列是从原序列的任意位置删除元素,相当于不一定是原序列中连续的元素。用以下思路来理解如何删除元素:
删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值。而对全局使用这样的删除操作,就可以得到最长摆动子序列。本题并未要求删除,只用求出长度即可。思路是从第二个开始计数,在计算是否有峰值的时候,大家知道遍历的下标 i ,计算 prediff(nums[i] - nums[i-1]) 和 curdiff(nums[i+1] - nums[i]),如果prediff < 0 && curdiff > 0 或者 prediff > 0 && curdiff < 0 此时就有波动就需要统计。具体要考虑三种情况
- 情况一:上下坡中有平坡
如下图数组[1,2,2,2,2,1]。
要删除前面三个或者后面三个2。如果按照原来的判断峰值方式会出错。在图中,当 i 指向第一个 2 的时候,prediff > 0 && curdiff = 0 ,当 i 指向最后一个 2 的时候 prediff = 0 && curdiff < 0。如果我们采用,删左面三个 2 的规则,那么 当 prediff = 0 && curdiff < 0 也要记录一个峰值,因为他是把之前相同的元素都删掉留下的峰值。所以我们记录峰值的条件应该是: (preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0),为什么这里允许 prediff == 0 ,就是为了 上面我说的这种情况。
2. 情况二:数组首尾两端
计算峰值至少需要三个节点,才能确定中间节点是否记录,那么数组的头尾节点如何处理计数?如果数组长度为2能不能统一到上述规则中?
前文已规定过:一端平一段上下坡也算峰值。那么最左端的开始节点可以默认为前面有一个等值的节点,这样就能把头节点算上。对于尾节点默认为一个峰值(count从1开始算,在遍历过程中如果curdiff=0不会记录,所以不用担心最后一个元素和倒数第二个元素相同)。这样两个节点的数组可以不加修改就整合到统一规则中。
3. 情况三:单调坡中有平坡
如果实时更新prediff,即把当前的curdiff赋值给prediff用于下一轮遍历,会存在以下问题:单调坡中如果存在平坡,会因为prediff由>0改为=0造成中间的节点也被判为峰值。因此正确的做法是只有当峰值发生变化的时候再改变prediff,开始的时候初始化为0(根据情况二分析)。
因此最终代码如下
class Solution {
public int wiggleMaxLength(int[] nums) {
if(nums.length == 1){
return 1;
}
int prediff = 0;
int curdiff = 0;
int count = 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){
count++;
prediff = curdiff;
}
}
return count;
}
}
4. 最大子序和
力扣
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
注意:不是遇到复数就从0开始计数count,因为下一个可能是正数把最大和给加回来甚至更高。
首先定义一个最大值,实时更新这个最大值。用count记录当前子序的和。遍历 nums,从头开始用 count 累积,如果 count 一旦加上 nums[i]变为负数,那么就应该从 nums[i+1]开始从 0 累积 count 了,因为已经变为负数的 count,只会拖累总和。如果count>最大值,及时记录。
class Solution {
public int maxSubArray(int[] nums) {
int res = Integer.MIN_VALUE;
int count = 0;
for(int i = 0; i < nums.length; i++){
count += nums[i];
if(count > res){
res = count;
}
if(count < 0){
count = 0;
}
}
return res;
}
}