贪心算法:指的是每一步都会选择最优解,但是合在一起不一样会产正最优解
贪心算法、回溯、动态规划的区别:
- 贪心:当下做局部最优判断,不能回退
- 回溯:可以回退,寻找解,不一定为最优解
- 动态规划:全局最优判断+回退
现在在题目中去体会什么是贪心算法:
1.在柠檬水摊上,每一杯柠檬水的售价为 5 美元。
顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。
每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。
注意,一开始你手头没有任何零钱。
如果你能给每位顾客正确找零,返回 true ,否则返回 false 。
示例 1:
输入:[5,5,5,10,20]
输出:true
解释: 前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。 第 4位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。 第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。由于所有客户都得到了正确的找零,所以我们输出 true。
解法:
该题为leetcode中简单类型的题,因此就主要说下,这里那个思想用到了贪心
当收到20美元时,我们优先给钱方式为10+5元 而不是5 5 5元,这里优先使用大面值的钞票,即是我们所提到的贪心算法思想。
2.给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins = [2], amount = 3
输出: -1
解法:
贪心(来自于leetcode中大佬的思维)
11. 想要总硬币数最少,肯定是优先用大面值硬币,所以对 coins 按从大到小排序
12. 先丢大硬币,再丢会超过总额时,就可以递归下一层丢的是稍小面值的硬币乘法对加法的加速 21. 优先丢大硬币进去尝试,也没必要一个一个丢,可以用乘法算一下最多能丢几个 k = amount / coins[c_index] 计算最大能投几个 amount - k * coins[c_index] 减去扔了 k 个硬币 count + k 加 k 个硬币 如果因为丢多了导致最后无法凑出总额,再回溯减少大硬币数量 最先找到的并不是最优解 31. 注意不是现实中发行的硬币,面值组合规划合理,会有奇葩情况 32. 考虑到有 [1,7,10] 这种用例,按照贪心思路 10 + 1 + 1 + 1 + 1 会比 7 + 7 更早找到 33. 所以还是需要把所有情况都递归完 ans 疯狂剪枝 41. 贪心虽然得不到最优解,但也不是没用的 42. 我们快速算出一个贪心的 ans 之后,虽然还会有奇葩情况,但是绝大部分普通情况就可以疯狂剪枝了
//参数解释,coins零钱容器,amount 总共的钱,index层数,count硬币数,ans最后返回结果
void coinChange(vector<int>& coins, int amount, int index, int count, int& ans)
{
if(amount==0)
{
ans = min(ans, count);
return;
}
//terminator
if (index == coins.size()) return;
for (int k = amount / coins[index]; k >= 0 && k + count < ans; k--)
{
//下到下一层
//drill down
coinChange(coins, amount - k * coins[index], index + 1, count + k, ans);
}
}
int coinChange(vector<int>& coins, int amount) {
if(amount==0)
return 0;
sort(rbegin(coins),rend(coins)); //排序 从大到小
int ans=INT_MAX;
coinChange(coins, amount, 0, 0, ans);
return ans == INT_MAX ? -1 : ans;
}
3.给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 =5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
解法:
1.若后一天比前一天价高,则为后一天减前一天即(前一天买入一天卖出)
2.若后一天比前一天价低,则不买卖
3.这里贪心算法的决策是:只加正数。
int maxProfit(vector<int>& prices) {
if(prices.size()==0) return 0;
int profit=0;
//for循环,时间复杂度为O(n) 空间为O(1)
for(int i=0;i<prices.size()-1;i++)
{
if (prices[i+1]-prices[i]>0) profit += (prices[i+1]-prices[i]);
}
return profit;
}
感谢阅读,欢迎大家讨论!