贪心算法(Greedy Algorithm)
,又名贪婪法,是寻找 最优解问题 的常用方法。
优点:
缺点:
没错,我们常见的选择排序就是运用了贪心算法的思想。
题目:
- 实现数字数组递增排序。
解答:
从数组的零下标开始,依次从后面找到最小的元素下标与当前位置的元素互换,这个在后面寻找最小元素的过程就是贪心的思想。
贪心策略
:寻找最小的元素,(贪心地)认定此元素就是当前位置的最小元素,然后遍历每一个位置。
public void choiceSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
int minIndex = i;
for (int j = i + 1; j < arr.length; j++) {
minIndex = arr[j] < arr[minIndex] ? j : minIndex;
}
if (minIndex != i) {
int tmp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = tmp;
}
}
}
题目:
有一个背包,容量由你自己输入,有n个物品,每个物品都具有容量与价值,这些都是由你自己输入的,请问,要怎么放物品到背包里,才能使得总价值最大呢,放入背包的总容量要小于等于背包的总容量。(如果一个物品放不下,则可以拆分成多个小块)
背包:M:100
物品:N:7
重量 价值
10 20
20 40
30 30
25 20
50 40
10 35
60 70
解答:
每个物品都具有自己的重量与价格,不妨计算出每个物品的单位价值。
然后我们将这些物品 按照单位价值递减排序。这样一来就简单了,只需用贪心算法,依次把最大单位价值的物品价值和重量相加 就行了。
贪心策略
:单位价值最大的物品,我们假设它就是最好的,直接把它放在背包里面。
public static void main(String[] args) {
int[][] items = new int[7][2];
items[0][0] = 10; items[0][1] = 20;
items[1][0] = 20; items[1][1] = 40;
items[2][0] = 30; items[2][1] = 30;
items[3][0] = 25; items[3][1] = 20;
items[4][0] = 50; items[4][1] = 40;
items[5][0] = 10; items[5][1] = 35;
items[6][0] = 60; items[6][1] = 70;
int capacity = 100;
System.out.println("背包的容量:" + capacity);
StringBuilder builder = new StringBuilder();
for (int[] item : items) {
builder.append(Arrays.toString(item));
}
System.out.println(items.length + " 个物品的重量、价值:" + builder.toString());
int maxValue = maxValue(items, capacity);
System.out.println("最大价值:" + maxValue);
}
public static int maxValue(int[][] items, int capacity) {
// 计算单位价值
double[] prices = new double[items.length];
Map<Double, List<Integer>> positionMap = new HashMap<>(items.length);
for (int i = 0; i < items.length; i++) {
prices[i] = 1.0 * items[i][1] / items[i][0];
List<Integer> positions = positionMap.getOrDefault(prices[i], new ArrayList<>());
positions.add(i);
positionMap.put(prices[i], positions);
}
// 排序
Arrays.sort(prices);
int weight = 0;
int maxValue = 0;
for (int i = prices.length - 1; i >= 0; i--) {
List<Integer> positions = positionMap.get(prices[i]);
if (positions != null) {
Integer position = positions.remove(0);
if (positions.size() == 0) {
positionMap.remove(prices[i]);
}
if (weight + items[position][1] < capacity) {
weight += items[position][0];
maxValue += items[position][1];
System.out.println("重量为 " + items[position][0] + ",价值为 " + items[position][1] + " 的物品被放入背包,剩余容量:" + (capacity - weight));
}
}
}
return maxValue;
}
执行结果:
322. 零钱兑换
假设你开了间小店,不能电子支付,钱柜里的货币只有 25 分、20分、10 分、5 分和 1 分 四种硬币,如果你是售货员且要找给客户 41 分钱的硬币,如何安排才能找给客人的钱既 正确 且硬币的个数又 最少?
我们看到这种题目可能第一个想法就是用 贪心算法
进行解决,其实不然,由于贪心算法不能进行回溯处理,所以并不能取得最优解。
那么不用贪心算法,应该用什么算法呢?其实有两种方法可以解决:
贪心
+回溯
,即 记忆化搜索
。动态规划
。代码实现需要注意以下几点:
class Solution {
public static void main(String[] args) {
int amount = 41;
int[] arr1 = {1, 5, 10, 20, 25};
System.out.println("零钱总数为:" + amount);
System.out.println("硬币面值为:" + Arrays.toString(arr1));
int result1 = coinChange(arr1, amount);
System.out.println("最少使用硬币数:" + result1);
}
public static int coinChange(int[] coins, int amount) {
if (amount == 0) {
return 0;
}
return handleCoin(coins, new int[amount], amount);
}
private static int handleCoin(int[] coins, int[] his, int coinAmount) {
if (coinAmount < 0) {
return -1;
}
if (coinAmount == 0) {
return 0;
}
if (his[coinAmount - 1] != 0) {
return his[coinAmount - 1];
}
int minCount = Integer.MAX_VALUE;
for (int coin : coins) {
int tmpMinCount = handleCoin(coins, his, coinAmount - coin);
if (tmpMinCount != -1 && tmpMinCount + 1 < minCount) {
minCount = tmpMinCount + 1;
}
}
his[coinAmount - 1] = minCount == Integer.MAX_VALUE ? -1 : minCount;
return his[coinAmount - 1];
}
}
执行结果:
代码实现需要注意以下几点:
class Solution {
public static void main(String[] args) {
int amount = 41;
int[] arr1 = {1, 5, 10, 20, 25};
System.out.println("零钱总数为:" + amount);
System.out.println("硬币面值为:" + Arrays.toString(arr1));
int result1 = coinChange(arr1, amount);
System.out.println("最少使用硬币数:" + result1);
}
public static int coinChange(int[] coins, int amount) {
// k-零钱和,v-最小零钱量
int[] his = new int[amount + 1];
Arrays.fill(his, amount + 1);
his[0] = 0;
for (int i = 1; i <= amount; i++) {
for (int coin : coins) {
if (coin <= i) {
his[i] = Math.min(his[i], his[i - coin] + 1);
}
}
}
return his[amount] == amount + 1 ? -1 : his[amount];
}
}
执行结果:
整理完毕,完结撒花~
参考地址:
1.小白带你学—贪心算法(Greedy Algorithm),https://zhuanlan.zhihu.com/p/53334049
2.贪心算法思想详解+示例代码,https://blog.csdn.net/jj6666djdbbd/article/details/126971331