写在前面
- 贪心的思想很多时候在于想到那个贪心的点上,而对徒手书写某些代码结构的能力并不做要求,个人认为需要的是你敏锐的意识到这个贪心的点在哪里。
- 列举出这几道典型题目作为回顾与复习。
题目列表
-
- 分发饼干
2. 376. 摆动序列
3. 402. 移掉K位数字
4. 55. 跳跃游戏
5. 45. 跳跃游戏 II
6. 452. 用最少数量的箭引爆气球
不直观,给个更直观的图:
思路分析
- 分发饼干:贪心点在于:尽可能小的饼干满足尽可能多的孩子。
- 摆动序列:贪心点在于:只计算摆动的长度,这里涉及一个类似数字电路里状态机,准确来讲是米粒型状态机的写法,在此类题目中很有用。建议掌握
- 移掉K位数字:贪心点在于:从高位向低位去,去的时候对比大小,去大的符合预期。
- 跳跃游戏:贪心点在于:如何不浪费跳跃距离,那么我们可以考虑从终点倒推起点,最后看起点是否索引为0即可。
- .跳跃游戏 II:贪心点在于:与上题相同,依旧在于不浪费跳跃距离,那么我们考虑当前跳跃是否为必要跳跃,注释的比较详细,见代码。
- 用最少数量的箭引爆气球:贪心点在于:是否需要增加弓箭手,单个弓箭手的最优射击范围的维护。
代码实现
-
- 分发饼干
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
// 排序操作
sort(g.begin(),g.end());
sort(s.begin(),s.end());
// 遍历
int child = 0;
int candy = 0;
while (child < g.size() && candy < s.size()) {
if (g[child] <= s[candy] ) {
child++;
}
candy++;
}
return child;
}
};
-
- 摆动序列
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
int len = nums.size();
if (len < 2) {
return len;
}
static const int BEGIN = 0;
static const int UP = 1;
static const int DOWN = 2;
int STATE = BEGIN;
int max_length = 1;
for (int i = 1; i < len; ++i) {
switch (STATE) {
case BEGIN:
if (nums[i - 1] < nums[i]) {
STATE = UP;
max_length++;
} else if (nums[i - 1] > nums[i]) {
STATE = DOWN;
max_length++;
}
break;
case UP:
if (nums[i - 1] > nums[i]) {
STATE = DOWN;
max_length++;
}
break;
case DOWN:
if (nums[i - 1] < nums[i]) {
STATE = UP;
max_length++;
}
break;
}
}
return max_length;
}
};
-
- 移掉K位数字
class Solution {
public:
string removeKdigits(string num, int k) {
vector<int> S;
string result = "";
for (int i = 0; i < num.size(); ++i) {
int number = num[i] - '0';
while ( (S.size() != 0) && (number < S[S.size() - 1]) && (k > 0) ) {
S.pop_back();
k--;
}
if (number != 0 || S.size() != 0) {
S.push_back(number);
}
}
while (S.size() != 0 && k > 0) {
S.pop_back();
k--;
}
for (int i = 0;i < S.size(); ++i) {
result.append(1,('0'+S[i]) );
}
if (result == "") {
result = "0";
}
return result;
}
};
-
- 跳跃游戏
class Solution {
public:
bool canJump(vector<int>& nums) {
int lastPos = nums.size() - 1;
for (int i = nums.size() - 2; i >= 0; i--) {
if (i + nums[i] >= lastPos) {
lastPos = i;
}
}
return lastPos == 0;
}
};
-
- 跳跃游戏 II
class Solution {
public:
int jump(vector<int>& nums) {
// 特况处理
if (nums.size() <= 1) {
return 0;
}
// 遍历,使用两个变量存储当前可以到达的最大距离和是否需要必要跳跃
int cur_max = nums[0];
int pre_max = nums[0];
int res = 1;
for (int i = 1; i < nums.size(); ++i) {
// 更新cur_max:之前需要依次必要跳跃,res增加1,并同步更新当前最远距离
if (i > cur_max) {
res++;
cur_max = pre_max;
}
// 更新pre_max以判断其是否需要用于更新当前最大距离
if (nums[i] + i > pre_max) {
pre_max = nums[i] + i;
}
}
return res;
}
};
-
- 用最少数量的箭引爆气球
bool cmp(const vector<int>& a,const vector<int>& b){
return a[1] < b[1];
}
class Solution {
public:
int findMinArrowShots(vector<vector<int>>& points) {
if (points.size() == 0) {
return 0;
}
// 根据左端点进行排序
sort(points.begin(),points.end(),cmp);
// 维护当前弓箭手最优射击区间
int shoot_num = 1;
int shoot_begin = points[0][0];
int shoot_end = points[0][1];
for (int i = 1; i < points.size(); ++i) {
if (points[i][0] <= shoot_end) {
shoot_begin = points[i][0];
if (shoot_end > points[i][1]) {
shoot_end = points[i][1];
}
} else {
shoot_num++;
shoot_begin = points[i][0];
shoot_end = points[i][1];
}
}
return shoot_num;
}
};