贪心算法详解:原理、应用场景及代码实现
创作时间:
作者:
@小白创作中心
贪心算法详解:原理、应用场景及代码实现
引用
CSDN
1.
https://blog.csdn.net/2301_79602614/article/details/138244968
贪心算法是一种在每一步选择中都采取当前状态下最好或最优的选择,从而希望导致结果是最好或最优的算法。这种算法通常用于求解优化问题,如最小生成树、背包问题等。
贪心算法的基本概念
贪心算法的核心思想可以概括为以下三个步骤:
- 将寻找最优解的问题分为若干个步骤
- 每一步骤都采用贪心原则,选取当前最优解
- 因为没有考虑所有可能,局部最优的堆叠不一定让最终解最优
贪心算法的应用场景包括:
- 背包问题:给定一组物品和一个背包,每个物品有一定的重量和价值,要求在不超过背包容量的情况下,尽可能多地装入物品。
- 活动选择问题:在一个活动集合中,每次只能参加一个活动,问如何安排时间以最大化所有活动的收益。
- 编辑距离问题:给定两个字符串,求它们之间的最小编辑距离(即将一个字符串转换为另一个字符串所需的最少操作次数)。
- 网络流问题:给定一张有向图和一些起点和终点,求最大流量。
- 找零问题:给定一定数量的硬币和需要找零的金额,求使用最少的硬币数。
贪心算法的常见问题及解答
- 贪心算法一定会找到最优解吗?
- 答:不一定。贪心算法只保证在每一步选择中都是最优的,但并不能保证整个问题的最优解。例如,背包问题中的贪心算法可能会导致最后一个物品没有被装入背包。
- 如何判断一个问题是否适合用贪心算法解决?
- 答:一个问题如果可以用递归的方式分解成若干个子问题,且每个子问题都有明确的最优解(即局部最优),那么这个问题就可以用贪心算法解决。
- 贪心算法的时间复杂度是多少?
- 答:贪心算法的时间复杂度取决于问题的规模和具体实现。一般来说,对于规模较小的问题,贪心算法的时间复杂度可以达到O(nlogn)或O(n^2);对于规模较大的问题,可能需要O(n^3)或更高。
贪心算法的具体实现
Dijkstra算法
while (!list.isEmpty()) {
// 选取当前【距离最小】的顶点
Vertex curr = chooseMinDistVertex(list);
// 更新当前顶点邻居距离
updateNeighboursDist(curr);
// 移除当前顶点
list.remove(curr);
// 标记当前顶点已经处理过
curr.visited = true;
}
需要注意的是,当图中存在负边时,Dijkstra算法可能无法得到正确的最短路径解。这是因为贪心原则会认为本次已经找到了该顶点的最短路径,下次不会再处理它(curr.visited = true)。相比之下,Bellman-Ford算法不会出错,因为它每次都处理所有边,但效率不如Dijkstra算法。
Prim算法
while (!list.isEmpty()) {
// 选取当前【距离最小】的顶点
Vertex curr = chooseMinDistVertex(list);
// 更新当前顶点邻居距离
updateNeighboursDist(curr);
// 移除当前顶点
list.remove(curr);
// 标记当前顶点已经处理过
curr.visited = true;
}
Kruskal算法
while (list.size() < size - 1) {
// 选取当前【距离最短】的边
Edge poll = queue.poll();
// 判断两个集合是否相交
int i = set.find(poll.start);
int j = set.find(poll.end);
if (i != j) { // 未相交
list.add(poll);
set.union(i, j); // 相交
}
}
其他贪心算法的例子
- 选择排序、堆排序
- 拓扑排序
- 并查集合中的 union by size 和 union by height
- 哈夫曼编码
- 钱币找零(change-making problem)
- 任务编排
- 求复杂问题的近似解
零钱兑换问题
零钱兑换II(LeetCode 518)
这是一个典型的动态规划问题,但也可以用贪心算法来尝试解决。下面是一个暴力递归的实现:
public int rec(int index, int[] coins, int remainder) {
// 1.情况1:剩余金额 < 0 - 无解
// 2.情况2:剩余金额 > 0 - 继续递归
// 3.情况3:剩余金额 = 0 - 有解
if (remainder < 0) {
return 0;
} else if (remainder == 0) {
return 1;
} else {
int count = 0;
for (int i = index; i < coins.length; i++) {
count += rec(i, coins, remainder - coins[i]);
}
return count;
}
}
但是这个代码在LeetCode上运行会超时,因为重复处理了很多次相同的操作。我们可以考虑用记忆化搜索或动态规划来优化。
零钱兑换(LeetCode 322)
这是一个求最小硬币数的问题,可以用动态规划来解决。下面是一个暴力递归的实现:
static int min = -1; // 需要的最少硬币数 2 3
public int coinChange(int[] coins, int amount) {
rec(0, coins, amount, new AtomicInteger(-1), new LinkedList<>(), true);
return min;
}
// count 代表某一组合 钱币的总数 可变的整数对象
public void rec(int index, int[] coins, int remainder, AtomicInteger count, LinkedList<Integer> stack, boolean first) {
if (!first) {
stack.push(coins[index]);
}
count.incrementAndGet(); // count++
if (remainder == 0) {
System.out.println(stack);
if (min == -1) {
min = count.get();
} else {
min = Integer.min(min, count.get());
}
} else if (remainder > 0) {
for (int i = index; i < coins.length; i++) {
rec(i, coins, remainder - coins[i], count, stack, false);
}
}
count.decrementAndGet(); // count--
if (!stack.isEmpty()) {
stack.pop();
}
}
贪心法求解零钱兑换(LeetCode 322)
贪心法在某些情况下可以快速得到解,但并不保证总是能得到最优解。下面是一个贪心算法的实现:
public int coinChange(int[] coins, int amount) {
int remainder = amount;
int count = 0;
for (int coin : coins) {
while (remainder - coin > 0) {
remainder -= coin;
count++;
}
if (remainder - coin == 0) {
remainder = 0;
count++;
break;
}
}
if (remainder > 0) {
return -1;
} else {
return count;
}
}
需要注意的是,贪心算法在某些情况下可能会得到错误的解,因为它没有考虑所有可能的组合。例如,对于输入[15, 10, 1]和金额21,贪心算法会得到错误的解,因为它没有“回头”机制来检查更优的组合。
热门推荐
烟花三月下扬州已经具象化了
颈椎不好引起的头晕头昏怎么治疗
清洁帮手,家用拖把选购攻略
蚂蚁集团公布种树8年成果:协议捐资超40亿,累计种树5.48亿棵
缓解眼压高的6个小方法
如何煎出多汁牛排?掌握火候与技巧的关键秘诀
劳务外包的工资能和正式员工一样么
医生解答:眼贴对眼睛的影响与使用注意事项
心理问题背后的情绪和需求
你的C++代码有多慢?使用 perf 精准揪出耗时函数!
行至第十季,“明侦”的稳与忧
如何开发一个自用的手机APP
舌头疼挂哪个科检查
如何管理收银机客户服务
氢化美缝剂和普通美缝剂有什么区别?
严苛乐评机构给Lady Gaga打8.0分?粉丝众筹请肌肉男乐评人吃饭!
中医按摩足跟痛
如何正确挑选地漏?实用技巧与注意事项指南
分子动力学仿真软件:AMBER二次开发_量子力学-分子力学(QM-MM)结合方法
《NBA2K25》测评:操作简化,动作丰富 年货游戏也有提升PC端终于开启次世代
WGCNA在单细胞空间数据分析中的运用
折叠屏手机弯折测试:衡量手机耐用性的关键环节
想让泰迪毛发更美?这些食物既实惠又有效!
脊索瘤手术如何治疗?
北方常见野菜的美味做法
新媒体运营的从业者应该具备哪些能力
云南产业新优势释放新动能
生命周期评估(LCA)、环境产品声明(EPD)和产品环境足迹(PEF)解读!
家常版水煮肉片,肉嫩的像豆腐一样。
张红甫教你做麻辣鲜香的水煮肉片