学习目的
1.理解这种经典算法的基础理论和应用场景
2.利用算法解决实际问题
(一)贪心算法解决的问题
数学归纳法;
反证法。
(二)回溯算法的基础
一般解题的步骤
①将问题分为若干个子问题
②求出适合的贪心策略
③求解出每一个子问题的最优解
④将局部最优堆叠为全局最优解
(三)例题
1.分发饼干
分发饼干
(1)题目分析
为了满足更多的小孩,就不要造成饼干的浪费。
子问题:从后向前用饼干依次满足小孩的胃口。
因为满足大胃口小孩的饼干一定能满足小胃口小孩的饼干。
(2)代码实现
a.遍历小孩的胃口数组
饼干的数组通过自减方式遍历
b.满足条件就计数的方法
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
//首先对两个数组进行排序
sort(g.begin(),g.end());
sort(s.begin(),s.end());
//定义饼干能满足小孩胃口的数组
int result = 0;
//数组长度,遍历饼干数组和遍历胃口数组不一样
//为每个小饼干找满足口最大的小孩
int size = g.size()-1;
int index = s.size()-1;
for(int i = size;i>-1;i--){
if(index>=0&&s[index]>=g[i]){
index--;
result++;
}
}
return result;
}
};
2.摆动序列
摆动序列
(1)题目分析
求连续递增递减序列的反面;
摆动序列:连续数字之间的差严格地在正数和负数之间交替;
用两个元素反应当前元素与两端元素的插值关系
(2)代码实现
可以通过动态规划和贪心算法求解,但是贪心算法的复杂度更低。
贪心步骤
让峰值尽可能保持峰值,删除单一坡度上的节点
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
if (nums.size() <= 1) return nums.size();
int curDiff = 0; // 当前一对差值
int preDiff = 0; // 前一对差值
int result = 1; // 记录峰值个数,序列默认序列最右边有一个峰值
for (int i = 0; i < nums.size() - 1; i++) {
curDiff = nums[i + 1] - nums[i];
// 出现峰值,这里的等号就是把可能出现连续相等的数值情况考虑进去,只需考虑一侧即可
if ((curDiff > 0 && preDiff <= 0) || (preDiff >= 0 && curDiff < 0)) {
result++;
preDiff = curDiff;
}
}
return result;
}
};