贪心算法
在对问题求解时,总是做出在当前看来是最好的选择,不从整体最优上加以考虑,所做的仅仅是在某种意义上的局部最优解。
没有固定的算法框架。贪心算法不是对所有问题都能的对整体最优解,选择贪心策略必须具备无后效性。
基本思路:
- 针对一组数据,我们定义了限制值和期望值,希望从中选出几个数据,在满足限制值的情况下,期望值最大。
- 尝试这个问题是否可以用贪心算法解决
- 我们举几个例子看下贪心算法产生的结果是否是最优的,大部分情况下,举几个例子验证下就昆虫,严格地证明贪心算法的正确性,是非常复杂的,需要涉及比较多的数学推理
存在的问题
- 不能保证求得的最后解是最佳的
- 不能用来求最大值最小值的问题
- 只能求满足某些约束条件的可行解的范围
实际上,用贪心算法解决问题的思路,并不总能给出最优解
使用贪心算法,给出的路径是 S-A-E-T 权值是9,最优解是6。贪心算法不成功的原因是,前面的选择,会影响后面的选择。
可适用于贪心的前提:
每一步局部最优,最后导致全局最优
是否可以用贪心算法:
- 直觉,根据直觉描述出来的算法,具备“只考虑当前,不考虑全局”的特点,可能就是贪心算法
- 如果不能举出反例,那这个问题可能具有“贪心算法性质”,可以尝试去做
严格证明贪心算法:
- 数学归纳法
- 反证法
一旦贪心选择性质不成立,可以考虑的另一种算法思想就是“动态规划”。动态规划在每一步做决策的时候,就不只考虑当前步骤的最优解。
贪心算法的应用:
- 对数据压缩编码的霍夫曼编码
- 求最小生成树的Prim算法和Kruskal算法
- 求最短路径的迪杰斯特拉算法
LeetCode上的贪心算法:
12,452,122,55,435,455,343,300
合并区间
- 前提:区间按照左端点排序
- 贪心策略:在右端点的选择中,如果产生交集,总是将右端点的数值更新成为最大的,这样就可以合并更多的区间,符合题意。
可以被合并的区间一定是有交集的区间,只需要岁所有的区间按照左端点升序排序,然后遍历。
如果当前遍历到的区间的左端点 > 结果集中最后一个区间的右端点,说明它们没有交集,此时把区间添加到结果集;
如果当前遍历到的区间的左端点 <= 结果集中最后一个区间的右端点,说明它们有交集,此时产生合并操作,即:对结果集中最后一个区间的右端点更新(取两个区间的最大值)。
class Solution560001{
public int[][] merge(int[][] intervals){
if (intervals.length<2){
return intervals;
}
// 按照区间的起始位置排序
Arrays.sort(intervals, Comparator.comparingInt(o -> o[0]));
List<int[]> res = new ArrayList<>();
res.add(intervals[0]);
for (int i = 1; i < intervals.length; i++) {
int[] curInterval = intervals[i];
// 每次新遍历到的列表与当前结果集中的最后一个区间的终止断点进行比较
int[] peek = res.get(res.size()-1);
if (curInterval[0] > peek[1]){
res.add(curInterval);
}else {
peek[1] = Math.max(curInterval[1], peek[1]);
}
}
return res.toArray(new int[res.size()][]);
}
}