贪心算法
贪心算法(Greedy Algorithm) 是一种基于贪心策略进行问题求解的算法。在贪心算法中,每一步都选择当前状态下最优的解,最终期望通过局部最优的选择达到全局最优。贪心算法通常不保证能够得到全局最优解,但在某些问题中,贪心算法能够得到足够好的解,并且具有高效性。
贪心算法的基本思路
建立解的选择集合。 对于问题中的每一个子问题,建立一个解的选择集合。
确定选择的标准。 定义一种选择标准,选择当前最优解。
选择当前最优解。 根据选择标准,从选择集合中选择当前最优解。
更新当前状态。 根据选择的解,更新当前问题的状态。
重复以上步骤。 重复执行上述步骤,直到达到最终的解或无法继续选择。
适用场景
贪心选择性质: 问题的最优解可以通过一系列局部最优的选择得到。
子问题无关性: 子问题的解不会影响到其他子问题的选择。
可行性: 对于每一个子问题,选择最优解后,问题的解仍然是可行的。
经典应用
活动选择问题(Activity Selection Problem): 选择一系列互不相容的活动,使得能够参与的活动数量最大。
背包问题的贪心解法: 贪心策略用于选择价值/权重最高的物品,以填满背包。
优缺点
贪心算法的优点:
贪心算法的缺点:
在一个非负整数 a 中,我们希望从中移除 k 个数字,让剩下的数字值最小,如何选择移除哪 k 个数字呢?
具体步骤如下:
初始化一个空栈,用于存放最终结果的数字。
从高位到低位遍历非负整数 a 的每一位。
如果栈不为空,且当前数字小于栈顶数字,弹出栈顶数字,直到栈为空或者已经移除 k 个数字。
将当前数字入栈。
如果仍需移除 k 个数字,从栈底开始弹出数字,直到移除 k 个数字。
构造最终的结果字符串。
package com.controller.bootweb.demo.dsa;
import java.util.Stack;
public class RemoveKDigits {
public static String removeKdigits(String num, int k) {
if (num == null || num.length() == 0 || k >= num.length()) {
return "0";
}
Stack<Character> stack = new Stack<>();
for (char digit : num.toCharArray()) {
while (!stack.isEmpty() && k > 0 && digit < stack.peek()) {
stack.pop();
k--;
}
stack.push(digit);
}
// 如果仍需移除 k 个数字,从栈底开始弹出数字
while (k > 0) {
stack.pop();
k--;
}
// 构造最终结果字符串
StringBuilder result = new StringBuilder();
while (!stack.isEmpty()) {
result.insert(0, stack.pop());
}
// 移除结果字符串前导的 '0'
int index = 0;
while (index < result.length() && result.charAt(index) == '0') {
index++;
}
result.delete(0, index);
return result.length() == 0 ? "0" : result.toString();
}
public static void main(String[] args) {
String num = "1432219";
int k = 3;
String result = removeKdigits(num, k);
System.out.println(result); // Output: "1219"
}
}
复制代码
假设有 n 个人等待被服务,但是服务窗口只有一个,每个人需要被服务的时间长度是不同的,如何安排被服务的先后顺序,才能让这 n 个人总的等待时间最短?
贪心策略是按照每个人需要服务的时间长度从小到大进行排序,然后按照排好序的顺序进行服务。这样可以最小化每个人的等待时间。
public class ShortestJobFirst {
public static int minimizeTotalWaitTime(int[] serviceTimes) {
if (serviceTimes == null || serviceTimes.length == 0) {
return 0;
}
Arrays.sort(serviceTimes); // 按照服务时间从小到大排序
int totalWaitTime = 0;
int currentWaitTime = 0;
for (int serviceTime : serviceTimes) {
currentWaitTime += serviceTime;
totalWaitTime += currentWaitTime;
}
return totalWaitTime;
}
public static void main(String[] args) {
int[] serviceTimes = {5, 2, 8, 4};
int result = minimizeTotalWaitTime(serviceTimes);
System.out.println("最小总等待时间:" + result); // 输出:最小总等待时间:32
}
}
复制代码
评论