贪心算法
引言
贪心算法是一种简单而有效的算法设计技巧,广泛应用于解决各种优化问题。其基本思想是通过每一步的局部最优选择,最终达到全局最优解。贪心算法通常不会回溯之前的决策,而是基于当前状态作出最优决策,因此其执行效率较高。
原理
贪心算法(Greedy Algorithm)是一种通过每一步的局部最优选择,最终达到全局最优解的算法范式。其核心思想可以概括为以下两点:
- 贪心选择性质:每一步都选择当前情况下看起来最好的选择,即局部最优解。
- 最优子结构性质:当一个问题的最优解包含其子问题的最优解时,称该问题具有最优子结构性质。贪心算法通过递归地求解子问题,并利用最优子结构性质,保证每一步的选择都是最优的。
由于贪心算法不回溯之前的决策,仅根据当前状态作出最优决策,这使得其执行效率较高,但也限制了其适用范围。贪心算法通常适用于满足贪心选择性质和最优子结构性质的问题,例如最小生成树、最短路径和任务调度等。
应用场景
贪心算法在许多领域都有广泛的应用,特别是在以下几个方面:
- 最小生成树: 在图论中,贪心算法经常用于构建最小生成树,例如 Prim 算法和 Kruskal 算法。这些算法通过每次选择权值最小的边来构建最小生成树,从而实现图的最优连通。
- 最短路径问题: 在图论中,Dijkstra 算法和 A* 算法等都是基于贪心策略的最短路径算法。它们通过每次选择当前距离最短的顶点来逐步确定起点到其他顶点的最短路径。
- 任务调度问题: 在任务调度问题中,贪心算法可以用于优化任务的执行顺序,以使得总执行时间最小化。例如,按照任务的截止时间或处理时间进行排序,然后依次执行。
- 背包问题: 在背包问题中,贪心算法可以用于近似求解,例如分数背包问题中的分数贪心算法。这种算法每次选择单位价值最高的物品放入背包中,以尽可能达到背包的容量限制并使总价值最大化。
- 区间调度问题: 在区间调度问题中,贪心算法可以用于确定最大数量的互不重叠的区间。例如,会议安排问题中,每次选择结束时间最早的会议安排,以尽可能安排更多的会议。
- Huffman 编码: Huffman 编码是一种用于数据压缩的贪心算法。它通过构建一棵最优前缀树来实现对字符的编码,使得出现频率较高的字符拥有较短的编码,从而实现数据的高效压缩。
实现贪心算法
本篇我们主要分享的是区间调度问题相关例题。
452. 用最少数量的箭引爆气球
我们以 [[10,16],[2,8],[1,6],[7,12]] 为例:
原气球的排列为:
题目要求求出引爆所有气球所必须射出的 最小 弓箭数
如果按照原来顺序去判断的话,很难找出有重复的气球,所以我们可以对气球先进行排序(按照左边界或者右边界排序都可以,本题我按照左边界排序来进行讲解)
排序后为:
排序了之后我们就可以从上往下遍历去判断是否重合了。
当下面的气球的左边界小于等于上面气球的右边界时,证明两个气球重合,可以用一支箭引爆。
当然下面一个气球有可能和上面两个气球都重合,如果只和上面一个气球重合而不和上上面气球重合的话,那么还需要额外的一支箭去引爆。为了实现判断,当两支气球重合时,我们可以把右边界缩小为两个气球右边界较小的一个值(因为此时新气球的左边界一定大于等于上面两个气球的左边界,所以不用判断),如果新气球左边界小于上面气球的右边界,那么就不需要额外的箭就能引爆。
遍历完所有的气球,我们便可以统计出需要的箭的数量。
下面为代码实现:
class Solution {
public int findMinArrowShots(int[][] points) {
if (points.length == 0)
return 0;
Arrays.sort(points, (a, b