贪心算法简介
目录
贪心策略
贪心的概念
解决问题的策略,从局部最优推到全局最优
贪心的特点
贪心策略的提出是没有标准与模板的,无法举一反三
贪心策略的正确性是没有保证的,可能得到错误的解法
贪心的步骤
把解决问题的过程分为若干步
解决的每一步都选择最优解法
希望得到全局的最优解
贪心的例子
示例一:找零问题
50块钱买4块钱的物品,用20、10、5、1块钱找零钱,求找的最少张数
20 + 20 + 5 + 1,共4张
如果用20、18、10、5、1来找零钱,此时贪心策略依旧是20 + 20 + 5 + 1
但显然18 + 18 + 10才是最优解法
示例二:最小路径和

示例三:背包问题

贪心的常用证明方法
数学中见过的所以证明方法

试题1:柠檬水找零

算法原理
解法:贪心策略
分类讨论

代码编写
class Solution
{
public:
bool lemonadeChange(vector<int>& bills)
{
int five = 0;
int ten = 0;
for(auto x : bills)
{
if(x == 5)
{
five++;
}
else if(x == 10)
{
if(five == 0)
{
return false;
}
five--;
ten++;
}
else
{
if(ten && five) // 优先判断 10 + 5 元(贪心)
{
ten--;
five--;
}
else if(five >= 3)
{
five -= 3;
}
else
{
return false;
}
}
}
return true;
}
};
贪心证明
证明策略:交换论证法

试题2:将数组和减半的最少操作次数

算法原理
解法:贪心
具体策略:每次挑选当前数组中最大的数减半,直到数组和减少到至少一半为止
优化:借助大根堆,堆顶元素就是要减半的数,将减半后的数再入堆

代码编写
class Solution
{
public:
int halveArray(vector<int>& nums)
{
priority_queue<double> heap;
double sum = 0.0;
for(int x : nums)
{
heap.push(x);
sum += x;
}
sum /= 2.0;
int count = 0;
while(sum > 0)
{
double t = heap.top() / 2.0;
heap.pop();
sum -= t;
count++;
heap.push(t);
}
return count;
}
};
贪心证明
证明方法:交换论证法

试题3:最大数

算法原理
排序本质:确定元素的先后顺序
排序规则:
- a 大于 b :a在前面 b在后面
- a 等于 b: 无所谓
- a 小于 b: b在前面 a在后面
优化一:把数字转换为字符串,然后比较字典序
优化二:[0,0]只需要返回0
代码编写
class Solution
{
public:
string largestNumber(vector<int>& nums)
{
// 优化:把所有的数转化成字符串
vector<string> strs;
for(int x : nums)
{
strs.push_back(to_string(x));
}
// 排序
sort(strs.begin(), strs.end(),
[](const string &s1, const string &s2)
{
return s1 + s2 > s2 + s1;
});
// 提取结果
string ret;
for(auto &s : strs)
{
ret += s;
}
if(ret[0] == '0')
{
return "0";
}
return ret;
}
};
贪心证明
证明方法:全序关系
完全性:从集合中任意挑两个元素,可以比较大小关系(A ≥ B 或 A ≤ B)
反对称性:两个元素既可以在前也可以在后,位置就无所谓(A ≥ B 且 A ≤ B → A == B)
传递性:A ≥ B 且 B ≥ C → A ≥ C

试题4:摆动序列

算法原理
统计出所有极大值和极小值点的个数


代码编写
class Solution
{
public:
int wiggleMaxLength(vector<int>& nums)
{
int n = nums.size();
if(n < 2)
{
return n;
}
int ret = 0, left = 0;
for(int i = 0; i < n - 1; i++)
{
int right = nums[i + 1] - nums[i];
if(right == 0)
{
continue;
}
if(right * left <= 0)
{
ret++;
}
left = right;
}
return ret + 1;
}
};
贪心原理
证明方法一:反证法
证明方法二:分类讨论
证明方法三:交换论证



2985

被折叠的 条评论
为什么被折叠?



