(笔试题)Best Time to Buy and Sell Stock III

本文介绍了一个经典的股票交易问题,即如何在给定一系列股票价格的情况下,通过至多两次买卖操作获得最大收益。采用动态规划的方法解决此问题,并提供了一段简洁高效的Java代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

</pre></h2><h2><span class="wmd-input-section" style="color:rgb(90,90,90); font-family:'microsoft yahei'; line-height:29.7px; white-space:pre-wrap; outline:none!important"><span style="font-size:18px"><span class="token p" style="outline:none!important">1.题目描述:</span></span></span></h2><div><span class="wmd-input-section" style="color:rgb(90,90,90); font-family:'microsoft yahei'; line-height:29.7px; white-space:pre-wrap; outline:none!important"><span class="token p" style="outline: none !important;"><span class="token p" style="color: rgb(90, 90, 90); font-family: 'microsoft yahei'; line-height: 29.7px; white-space: pre-wrap; outline: none !important;"><span style="font-size:14px;">已知一支股票连续n天的价格走势,以长度为n的整数数组表示,数组中第i个元素(prices[i])代表该股票第i天的股价。 假设你一开始没有股票,但有至多两次买入1股而后卖出1股的机会,并且买入前一定要先保证手上没有股票。若两次交易机会都放弃,收益为0。 设计算法,计算你能获得的最大收益。 输入数值范围:2<=n<=100,0<=prices[i]<=100。</span></span><span style="font-size: 18px;"></span></span></span></div><h2><span class="wmd-input-section" style="color:rgb(90,90,90); font-family:'microsoft yahei'; line-height:29.7px; white-space:pre-wrap; outline:none!important"><span style="font-size:18px"><span class="token p" style="outline:none!important">2.分析:</span></span></span></h2><p><span class="wmd-input-section" style="color:rgb(90,90,90); font-family:'microsoft yahei'; line-height:29.7px; white-space:pre-wrap; outline:none!important"><span style="font-size:14px"><span class="token p" style="outline:none!important">实际上是LeetCode的题目,原题链接:<span class="token url" style="text-decoration:underline; outline:none!important">http://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/</span></span><span class="token lf" style="outline:none!important"></span><span class="token hr" style="outline:none!important">***</span></span></span></p><p><span class="wmd-input-section" style="color:rgb(90,90,90); font-family:'microsoft yahei'; line-height:29.7px; white-space:pre-wrap; outline:none!important"><span style="font-size:14px"><span class="token lf" style="outline:none!important"></span><span class="token p" style="outline:none!important">这道题是Best Time to Buy and Sell Stock的扩展,现在我们最多可以进行两次交易。我们仍然使用动态规划来完成,事实上可以解决非常通用的情况,也就是最多进行k次交易的情况。</span><span class="token lf" style="outline:none!important"></span><span class="token p" style="outline:none!important">这里我们先解释最多可以进行k次交易的算法,然后最多进行两次我们只需要把k取成2即可。我们还是使用“局部最优和全局最优解法”。我们维护两种量,一个是当前到达第i天可以最多进行j次交易,最好的利润是多少(global<span class="token linkref" style="outline:none!important"><span class="token ref-start" style="outline:none!important"><span class="token md md-bracket-start" style="outline:none!important">[</span><span class="token md md-underlined-text" style="color:inherit; text-decoration:underline; outline:none!important">i</span><span class="token md md-bracket-end" style="outline:none!important">]</span></span><span class="token ref-end" style="outline:none!important"><span class="token md md-bracket-start" style="outline:none!important">[</span><span class="token md md-href" style="outline:none!important">j</span><span class="token md md-bracket-end" style="outline:none!important">]</span></span></span>),另一个是当前到达第i天,最多可进行j次交易,并且最后一次交易在当天卖出的最好的利润是多少(local<span class="token linkref" style="outline:none!important"><span class="token ref-start" style="outline:none!important"><span class="token md md-bracket-start" style="outline:none!important">[</span><span class="token md md-underlined-text" style="color:inherit; text-decoration:underline; outline:none!important">i</span><span class="token md md-bracket-end" style="outline:none!important">]</span></span><span class="token ref-end" style="outline:none!important"><span class="token md md-bracket-start" style="outline:none!important">[</span><span class="token md md-href" style="outline:none!important">j</span><span class="token md md-bracket-end" style="outline:none!important">]</span></span></span>)。下面我们来看递推式,全局的比较简单,</span></span></span></p><p></p><pre code_snippet_id="1683696" snippet_file_name="blog_20160514_2_9235553" name="code" class="plain">                                                  global[i][j]=max(local[i][j],global[i-1][j]),


也就是去当前局部最好的,和过往全局最好的中大的那个(因为最后一次交易如果包含当前天一定在局部最好的里面,否则一定在过往全局最优的里面)。对于局部变量的维护,递推式是

                                         local[i][j]=max(global[i-1][j-1]+max(diff,0),local[i-1][j]+diff)

也就是看两个量,第一个是全局到i-1天进行j-1次交易,然后加上今天的交易,如果今天是赚钱的话(也就是前面只要j-1次交易,最后一次交易取当前天),第二个量则是取local第i-1天j次交易,然后加上今天的差值(这里因为local[i-1][j]比如包含第i-1天卖出的交易,所以现在变成第i天卖出,并不会增加交易次数,而且这里无论diff是不是大于0都一定要加上,因为否则就不满足local[i][j]必须在最后一天卖出的条件了)。

3.实现

<span style="font-size:18px;">public int calculateMax(int[] prices) {
		if(prices==null || prices.length==0)  
        return 0;  
    int[] local = new int[3];  
    int[] global = new int[3];  
    for(int i=0;i<prices.length-1;i++)  
    {  
        int diff = prices[i+1]-prices[i];  
        for(int j=2;j>=1;j--)  
        {  
            local[j] = Math.max(global[j-1]+(diff>0?diff:0), local[j]+diff);  
            global[j] = Math.max(local[j],global[j]);  
        }  
    }  
    return global[2];  
    }</span>

可以看到,这里的模型是比较复杂的,主要是在递推式中,local和global是交替求解的。不过理清思路之后,代码是非常简练的,不禁感叹算法真是牛逼哈,这么个复杂生活问题几行代码就解决了。参考资料:http://blog.youkuaiyun.com/linhuanmars/article/details/23236995

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值