Leetcode刷题系列(六)贪心算法
如何从局部最优达到全局最优解?举反例和对数器来进行证明。在某一个标准下, 优先考虑最满足标准的样本, 最后考虑最不满足标准的样本, 最终得到一个答案的算法, 叫作贪心算法。
也就是说, 不从整体最优上加以考虑, 所做出的是在某种意义上的局部最优解。
Leetcode455 分发糖果
对于给定的糖果和孩子胃口,看能最多满足多少孩子。
解题思路:将可以满足孩子的最小糖果分给该孩子,则可以使得满足的孩子数最大。
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 cookie = 0;
while (child < g.size() && cookie < s.size()){
if (s[cookie] >= g[child]){
child++;
}
cookie++;
}
return child;
}
};
Leetcode376 摇摆序列
解题思路如下
方法一:状态机模型。
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
if (nums.size() < 2) return nums.size();
const int BEGIN = 0;
const int UP = 1;
const int DOWN = 2;
int STATE = BEGIN;
int maxLen = 1;
for (int i = 1; i < nums.size(); i++){
switch(STATE){
case BEGIN:
if (nums[i] > nums[i-1]){
maxLen++;
STATE = UP;
}
else if (nums[i] < nums[i-1]){
maxLen++;
STATE = DOWN;
}
break;
case UP:
if (nums[i] < nums[i-1]){
maxLen++;
STATE = DOWN;
}
break;
case DOWN:
if (nums[i] > nums[i-1]){
maxLen++;
STATE = UP;
}
break;
}
}
return maxLen;
}
};
方法二:贪心算法。遍历数组,比较当前差值与前一个差值的正负,若符号相反,序列加一,反之,继续遍历。
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 = 1; i < nums.size(); i++){
curDiff = nums[i] - nums[i-1];
if ((curDiff >= 0 && preDiff < 0) || (curDiff <= 0 && preDiff > 0)){
result++;
preDiff = curDiff;
}
}
retrurn result;
}
};
Leetcode53 最大子序和
解题思路:
方法一:贪心算法。将数组看做多个累加和
- 当前统计累加和,大于上一个累加和,则保存
- 当前统计累加和,小于0(则表示该数为负值,且该负值大于当前累加和),放弃该数值,查找下一个累加和
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int result = INT_MIN;
int count = 0;
for(int i = 0; i < nums.size(); i++){
count += nums[i];
if (count > result) result = count;
if (count < 0) count = 0;
}
}
};
方法二:动态规划。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
vector<int> dp(nums.size(), 0);
dp[0] = nums[0]; // 第1个子序和为 nums[0]
int result = nums[0]; // 最大子序和为 nums[0]
for (int i = 1; i < nums.size(); i++){
// 最大子序和:当前数与前一个子序和相加 : 当前数 的最大值
dp[i] = max(dp[i-1] + nums[i], nums[i]);
if (result < dp[i]) result = dp[i];
}
return result;
}
};
Leetcode122 买卖股票的最佳时机II
解题思路
方法一:贪心算法。在后一天收益 - 前一天收益为正时,则卖出,累积为最优收益。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int res = 0;
for (int i = 1; i < prices.size(); i++){
res += max(prices[i] - prices[i-1], 0);
}
return res;
}
};
Leetcode55 跳跃游戏
解题思路:贪心算法。将问题转化为覆盖问题,当可以覆盖最后一个数,则返回true。
class Solution {
public:
bool canJump(vector<int>& nums) {
int cover = 0;
if (nums.size() == 1) return true;
for (int i = 0; i <= cover; i++){
cover = max(i + nums[i], cover);
if (cover >= nums.size() - 1) return true;
}
return false;
}
};
跳跃游戏II
解题思路:贪心算法。遍历数组,记录每个值的最远跳跃位置,记录该区间,在该区间内的最远跳跃位置大于记录的值,则更新该值。
class Solution {
public:
int jump(vector<int>& nums) {
int end = 0;
int maxPos = 0;
int res = 0;
for (int i = 0; i < nums.size() - 1; i++){
maxPos = max(nums[i] + i, maxPos);
if (i == end){
end = maxPos;
res++;
}
}
return res;
}
};
练习
- 旋转词:KMP算法。首先将字符串本身相连,如
cdab
修改为cdabcdab
,则新字符串任意长度为4的子串为原字符串的旋转词。