[leetcode122].为何此时贪心解是最优解 ?

【不知道是不是我想太多了,还是脑抽了?】
今天做了一个有意思问题,即122. Best Time to Buy and Sell Stock II 。简单地用中文描述问题,也就是用[ a1,a2,...,an ]表示一支股票在 n 个时刻的价格,问如何买卖股票可以使得收益最大。比如[1,2,6,8,9],可以在1的时候买入6的时候卖出,8的时候买入,9的时候卖出,此时收益为5+1=6。

本问题虽然很快就猜到一个贪心解,且看起来非常显然的解,并且完美地AC了。

class Solution(object):
    def maxProfit(self, prices):
        ans=0
        if len(prices)<=1:
            return 0
        for x in range(1,len(prices)):
            if prices[x]-prices[x-1]>=0:
                ans+=prices[x]-prices[x-1]
        return ans

绝大多数的博客、问题的discuss以及官网给出的解答都是仅仅一个贪心的策略(没有探讨为何是最优),即将所有最大的上升子区间加起来,如图所示,即将所有的上升区间
[leetcode122].为何此时贪心解是最优解 ?_第1张图片
加起来,说实话这看起来很有道理。毕竟满足我们的常识:在最低价的时候买入,在最高价的时候卖出(如果我们能预知未来,恰好此题可以预知未来),看图也是很明显的。

但是我想,这不过是给出了一个贪心解,如何证明它是最优的呢?这个问题难道真的那么简单吗?为了逻辑的完整性,我们必须证明这样的构造(方法)恰好就是最优解,我下午思考了若干种情况,分别分类讨论了一下,搞了很久(是不是我想太多了?)

实际上现在我们的问题无非就是将数组划分为若干个“持股区间”,在左端点上买入,右端点上卖出,找出使得收益最大的“持股区间”。受到狗蔡的启发,实际上我发现只要讲问题足够好地数学化就可以了,我们设给定的数组为[ a1,a2,...,an ],设最优的“持股区间”为 X (实际上这样的区间是存在的,因为区间的总数有限,可以用隔板法可以得出区间总数),将其划分为 n1 个小区间,即[ a1,a2 ],…,[ an1,an ],设示性函数:

χ[ai+1,ai]={1,[ai+1,ai]X0,[ai+1,ai]⊄X

那么我们的目标函数就是:

maxi=1n1(ai+1ai)χ[ai+1,ai]

很显然,这已经是一个0,1规划问题。另外我们来看实际上如果一个连续的区间[ a1,a2 ],[ a2,a3 ]都是 X 的子集的话,可以看成是[ a1,a3 ]符合我们的想法。由于示性函数是非负的,我们可以放缩它为:
i=1n1(ai+1ai)χ[ai+1,ai]=+Δaχ+Δaχ+Δaχ+Δa

等号成立条件为 (ai+1ai)0 的区间都使示性函数为1,否则为0,这恰好就是贪心算法的解。最优性得证。

你可能感兴趣的:(算法学习)