贪心算法理解及例题分析

贪心算法

大多数算法基于以下4种算法:
(1)贪心算法;
(2)分治算法(递归);
(3)动态规划(DP);
(4)穷举。
现在说贪心算法。

一、贪心算法的主要思路:

贪心算法主要思路是:
(1)把求解的问题分成若干个子问题;
(2)对每个子问题求解,得到子问题的局部最优解;
(3)把子问题的局部最优解合成原来问题的一个解。

从网上搜索贪心算法,基本都能搜到下面这段:

所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,它所做出的仅仅是在某种意义上的局部最优解。

就是说,贪心算法所得出的解,不一定是全局最优解。初看不理解,为啥得不到全局最优解呢?看过别人写的文章才知道,这跟子问题最优解的选择有关。贪心算法其实是动态规划(DP)的一种特殊情况,它的关键词是“局部最优”,每次只做当前对于自己最“有利”的选择,而动态规划则是要寻找“全局最优”,并且一定能找到“全局最优解”。

简言之,贪心算法比较符合人的思维,即每次都选择最有利于自己的选项,不考虑其他方面,也不考虑未来会怎样。

二、为什么要使用贪心算法?

既然贪心算法都不能保证得出全局最优解,为什么还要用它呢?因为如果直接求解全局最优解,可能时间复杂度和计算量都过于庞大,那么可以退而求其次,牺牲全局最优解来换取省力,不要求一定要得出全局最优解,只要趋近于最优解就可以。就像本来我应该拿100元工资(全局最优解)的,但是要大费周折,我还可以选择拿99块钱工资(局部最优解),却可以省下大量的精力,虽然钱少了,但我未尝不乐意。

三、问题是否适用于贪心算法?

“对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。”即求解一个问题能否用贪心算法,要看此问题的最优解是否能从子问题的最优解中得出来。判断一个问题是否适用贪心算法的难点就在于此,你想用贪心算法,又不能保证得出的解一定是整个问题的最优解,那肯定不合适啊。使用贪心算法只能尽可能地去求解趋近于全局最优解的解。

四、举个生活中的栗子

有1毛、5毛、1元、5元、10元、20元、50元、100元的人民币若干,现在想要拿出267.3元支付,要求纸币的张数要最少,应该怎样选择?生活常识告诉我们,应该从面额大的往小的一步步来选。先选两张100的,再选一张50的,再选一张10元的,再选一张5元的,再选两张一元的,最后选三张1毛的。这每一次选择都是一个子问题,都进行了一次贪心算法,即在不能超过总金额的前提下,每次都优先选择面值最大的人民币。

五、举个栗题

题目来源于Leetcode第122题:买卖股票的最佳时机 II

描述:

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:
输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

题目很好理解,下面用贪心算法的思路来分析。

1.题目的全局最优解是:最大化的利润。
2.把总问题分解为子问题:每次只考虑今天买明天卖能不能获利,只要能获利,那我今天就买,不考虑以后的事。
3.子问题最优解合成全局最优解:每个子问题获得的利润加起来就是最大化的利润。

代码也很简单,就6行:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        int sum = 0;//总利润
        for(int i=0;i < len-1;++i){
            if(prices[i+1]-prices[i] > 0) sum += prices[i+1] - prices[i];
        }
        return sum;
    }
};

六、另外的栗子

是Leetcode题目,见我的博客解体思路2,传送门->53.最大子序和
另一道:->455.分发饼干

最后,欢迎留言批评指证。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值