376摆动序列 1.理解摆动序列的判别条件 2.注意均为0的特殊情况,所以在更新前后差值时需要注意特殊条件
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
// 提前剪枝:数组长度≤1时直接返回自身长度
if(nums.size() <= 1) return nums.size();
int pre_diff = 0; // 上一个非0的差值
int cur_diff = 0;
int result = 1; // 至少有1个元素
for (int i = 0; i < nums.size() - 1; i++) {
cur_diff = nums[i+1] - nums[i];
// 仅当cur_diff≠0,且与pre_diff异号时,才统计摆动
if ((pre_diff >= 0 && cur_diff < 0) || (pre_diff <= 0 && cur_diff > 0)) {
result++;
pre_diff = cur_diff; // 仅满足条件时更新pre_diff(跳过差值为0的情况)
}
// 关键:cur_diff=0时,不更新pre_diff,保留上一个非0差值
}
return result;
}
};
53.最大子数组和 重点在于怎么做到局部最优,注意我们是用cur来记录当前最大子序列之和的,所以怎么才是最大。两种方式,一种是通过和记录的result进行比较,将较大值迭代更行。另外一种,即cur小于0时,负数和是越加越小的,那么就没有必要对接下来的子序列进行累加,直接从新的子序列开始累加就行
class Solution {
public:
int maxSubArray(vector<int>& nums) {
//暴力解法的n平方复杂度不适用,下面可以改造成n的时间复杂度
//本题的特殊在于,我们仅仅需要理解什么时候时局部最优,同时记录
int result=nums[0];
int cur=0;
//开始遍历nums
for(int i=0;i<nums.size();i++){
cur=cur+nums[i];//cur此时为子序列之和
//更新result
if(cur>result) result=cur;
//重点在这里,怎么使cur移动并达成局部最优了?
if(cur<0) cur=0;//从这里可以看出,当cur<0时,总和不加就是最小,也就达成了局部最优
}
return result;
}
};
122 买卖股票的最佳时机 这里要扭转一个观点,就是一直持有股票是不是会盈利!!!这里完全是错的,我们是要和下一天做比较,所以,我们每次都是直接取两点进行对比,有盈利我们买入卖出,没有就舍弃,而不是像个预言家一样傻傻地去预测!!思考今天我买了什么时候卖最好,那始终都不是局部最优观点,贪心算法的实质要的就是局部最优,只比较当天最佳选择
class Solution {
public:
int maxProfit(vector<int>& prices) {
//遍历数组将正数差累加即可
int result=0;
for(int i=0;i<prices.size()-1;i++){
result+=max(prices[i+1]-prices[i],0);//注意,这里采用贪心算法,局部最优就是当天和前一天的最大利差,亏损舍弃,盈利计入
}
return result;
}
};
55.跳跃游戏 1.理解跳跃的范围,使用贪心算法跟新 2.循环遍历必须摒弃固有思维遍历整个向量,这道题的破题点在于理解i必须在cover内移动
class Solution {
public:
bool canJump(vector<int>& nums) {
if(nums.size()==0) return false;
//本质同股票买入时机区别不大,移动下标更新最大区间即可
int cover=0;
for(int i=0;i<=cover;i++){//必须注意,i只能在cover内移动!!!
cover=max(cover,i+nums[i]);
if (cover >= nums.size() - 1) return true; // 说明可以覆盖到终点了
}
return false;
}
};
45。跳跃游戏
此题思路重点在于通过递接两个最大覆盖范围,来减少步数,并不是要求寻找最小步数路径,严格的话确实可以做到在O(n)时间内
class Solution {
public:
int jump(vector<int>& nums) {
//通过前后两个覆盖值来记录跳跃步数,这里也是要摆脱常规思想:必须寻找到最佳路径之后记录。但是,在算法当中,这并不需要我们寻找最佳路径
//剪支
if(nums.size()==1) return 0;
int cover=0;//用于记录当前可以移动的范围
int nextcover=0;//用于记录下一跳可以覆盖的范围
int result=0;//记录跳跃步数
for(int i=0;i<nums.size();i++){
//采用贪心算法获取下一跳的最大覆盖范围
nextcover=max(i+nums[i],nextcover);
if(i==cover){//到达当前最大覆盖范围
result++;//步数加一
cover=nextcover;//置换最大跳跃范围
if(nextcover>=nums.size()-1) break;
}
}
return result;
}
};