文章目录
贪心
刷题或者面试的时候,手动模拟一下感觉可以局部最优推出整体最优,而且想不到反例,那么就试一试贪心。
如果找到局部最优,然后推出整体最优,那么就是贪心
贪心没有套路,说白了就是常识性推导加上举反例。
分发饼干
小饼干先喂饱小胃口
摆动数列
去重后会比较好做
贪心思路
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
//去重
int i = 0, j = 0,last= 1001;
for(; j < nums.size(); j++){
if( last != nums[j]){
nums[i] = nums[j];
last = nums[i];
i++;
}
}
//新数组【0,i)
int n = i;
if(n == 1) return 1;
if(n == 2 && nums[0] != nums[1]) return 2;
if(n == 2 && nums[0] == nums[1]) return 1;
int le = 0, ri ,cnt = 2; //cnt是为了把两个端点算进来
for(i = 0 ;i < n-1; i++){
ri = nums[i+1] - nums[i];
if(ri * le < 0){ //一正一负时
cnt++; //统计峰值
}
le = ri;
}
return cnt;
}
};
最大子数组和
一开始拿到这道题的时候,时想着滑动窗口来做来着,但是后面想了想不行,回去看看了以前的滑动窗口题发现他们特征如下
- 都是‘最小’ 的 – 本题是最大
- 在符合条件的时候才会移动左指针 – 没有所谓的条件
贪心:
贪心的思路为局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。从而推出全局最优:选取最大“连续和”
买股票的最佳时机II
只收集每天的正利润,最后稳稳的就是最大利润
跳跃游戏
关键是理解跳跃的范围
*跳跃游戏
还是比较巧的,细节挺多的,容易踩坑拿不到满分 – last 和 ans的初值
真正解题的时候,要从覆盖范围出发,不管怎么跳,覆盖范围内一定是可以跳到的,以最小的步数增加覆盖范围,覆盖范围一旦覆盖了终点,得到的就是最少步数!
这里需要统计两个覆盖范围,当前这一步的最大覆盖和下一步最大覆盖。
如果移动下标达到了当前这一步的最大覆盖最远距离了,还没有到终点的话,那么就必须再走一步来增加覆盖范围,直到覆盖范围覆盖了终点。
关键是理解覆盖范围,需要好好的品
K次取反后最大化的数组和
贪心的思路,局部最优:让绝对值大的负数变为正数,当前数值达到最大,整体最优:整个数组和达到最大。
[ 加油站]
是一道不好理解的题
当totalsum大于0说明肯定有一种解法能走完 当做一个结论吧,可以举个例子
分发糖果
第一次遇见这种类型的题 一开始感觉还是比较难的
主要就是要分成两个过程来看,不要想着一下子就能解决它
还要注意for循环的边界(if) 确保所有想访问到的元素都能访问到
这道题目一定是要确定一边之后,再确定另一边,例如比较每一个孩子的左边,然后再比较右边,如果两边一起考虑一定会顾此失彼。
柠檬水
很简单一道题哈哈哈
*根据身高重建队列
很少做这种题,很巧,也是一个两个维度的题,不过很难想到是两个维度
本题有两个维度,h和k
如果按照k来从小到大排序,排完之后;,会发现k的排列并不符合条件,身高也不符合条件,两个维度哪一个都没确定下来。
那么按照身高h来排序呢,身高一定是从大到小排(身高相同的话则k小的站前面),让高个子在前面。
意思就是说安排k排序,再插入元素,这样的话k就乱了,身高也是
但是先根据身高排序,因为我们遍历的时候是按照身高来遍历的,后面插入的元素即使插入到我们新数组的前面,也不会影响k
(因为插入的h肯定比新数组的值都小)
vector.insert(xx.beging()+插入的下标,要插入的元素) – vector插入还是比较慢的用链表会更快
小总结
用最小数量的箭引爆气球
判断重叠区间问题
一开始想到贪心了,但是不知道该怎么实现,也不知道这个贪心是否真的可以ac(没考虑到连环重合)
局部最优:当气球出现重叠,一起射,所用弓箭最少。全局最优:把所有气球射爆所用弓箭最少。
无重叠区间
和上一题差不多,直接秒了!哈哈哈
我的思路:排序后,两个临近有重叠的区间肯定要删一个,然后我们 ‘删’ 右区间大的区间
划分字母区间
不是很难哈哈哈
我的贪心思路:让尽可能少的字母(种类)在一个片段中,一达到分割条件 就马上分割
老师的思路:
合并区间
也是成功的a了出来
也是一道重叠问题,好像重叠问题很多都要排序,最后都要处理一下最后一步(循环从[0,size)
我的思路: 就是把覆盖的都合并了,然后再加入ans
class Solution {
public:
vector<vector<int>> ans;
vector<int> area;
static bool cmd(vector<int>& x, vector<int>& y){
if(x[0] != y[0]) return x[0] < y[0];
return x[1] < y[1];
}
vector<vector<int>> merge(vector<vector<int>>& intervals) {
if(intervals.size() == 1) return intervals;
sort(intervals.begin(), intervals.end(), cmd);
int left = 0,flag = 0;
for(int i=0;i<intervals.size()-1 ;i++){
if(flag == 0) left = intervals[i][0]; //表明上次不是重叠的区间,可以更新
if(intervals[i][1] >= intervals[i+1][0]){ //重叠时
intervals[i+1][1] = max(intervals[i+1][1], intervals[i][1]);//取最大的
flag++; //保留left的值
}else{
area.push_back(left),area.push_back(intervals[i][1]);
ans.push_back(area);
area.clear();
flag = 0; //可以更新left的值了
}
}
//特殊处理最后一个区间的情况
if(flag != 0){ //重叠时
area.push_back(left),area.push_back(intervals[intervals.size()-1][1]);
ans.push_back(area);
}else{ //不重叠时
ans.push_back(intervals[intervals.size()-1]);
}
return ans;
}
};
老师代码,真的是很简洁啊
老师思路:第一个区间直接加(自己肯定不重叠),遇到重叠的直接更新答案,不重叠的直接加入ans
少了边界处理,真的很优雅QAQ
单调递增的数字
没a出来 主要有两个原因吧
- 贪心错了,没考虑到 200 -> 190的情况 – mark的后面应该都为9
- 不知道前一位减减后 ,前导0怎么处理 – 当时想复杂了
思路还是很巧的
还学到两个很重要的API
to_string – 将 int转为string
stoi – 将string转为int
小总结
局部最优 - > 全局最优!!
此文章用于笔者记录学习,也希望对你有帮助