leetcode309&121&122.Best Time to Buy and Sell Stock 问题

这篇博客探讨了LeetCode上的几个股票交易问题,包括Best Time to Buy and Sell Stock系列,重点在于如何使用动态规划求解最大利润。文章详细解释了动态规划的状态转移方程,并提供了简化空间复杂度的方法。还提到了其他类似问题的解决方案,如Kadane's Algorithm,并讨论了贪婪算法在解决此类问题中的应用。

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

本次总结的是leetcode上著名的几个问题:Best Time to Buy and Sell Stock 1,2
Best Time to Buy and Shell Stock With Cooldown问题。

问题的大概框架就是,
给你一个代表每天物品价格的数组,你可以买,卖商品,要求得到最大的收益。

这里先来谈一下这个问题:
Best Time to Buy and Sell Stock with Cooldown
Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions:

You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)
Example:

prices = [1, 2, 3, 0, 2]
maxProfit = 3
transactions = [buy, sell, cooldown, buy, sell]

大体上是说,你可以进行多次交易,但是在每次卖掉商品的时候,你不能在下一天买商品,必须隔一天,称为cooldown(又称为rest)

在这里讲诉一下最高赞的答案,本人觉得简直是醍醐灌顶的一个答案。
首先,这种类型的题明显是动态规划的题,这道题明显提到你可以尽可能多的进行交易,这样看来如果想讨论交易本身的话有点困难,但是我们可以很清楚的知道每种交易情况序列的最后状态是什么。很明显,有三种状态:buy,sell,cooldown.那么,我们从这三种情况开始入手,
1. buy: buy的状态无非就是从cooldown转移来, 或者从上一个buy转移来的。那么,可以很轻松的写出递推公式:buy[i]=max(cooldown[i-1]-price,buy[i-1])。
2. sell: sell可以由buy,sell转移来的。那么,sell的递推公式就为:sell[I]=max(buy[i-1]+price,sell[i-1])。
3. cooldown: cooldown的转移状态就多了,cooldown[i]=max(buy[i-1],sell[i-1],cooldown[i-1])
这里可以看到三种状态太多了,能不能简化一下,比如说{buy,cooldown,buy,cooldown….}. 这样的循环购买明显不会发生的。
那么对于cooldown来说,就只有,cooldown[i]=max(sell[i-1],cooldown[i-1])
因为cooldown[i]=cooldown[i-1]相当于一直休息,休息不会对金额的支出和收入产生影响,所以不影响最终的maxPro.又由于,sell的后一天一定会cooldown,所以可以得到最终两个递推式:
buy[i]=max(sell[i-2]-price,buy[i-1])
sell[i]=max(buy[i-1]+price,sell[i-1])
由于buy[i]只取决于sell[i-2],buy[i-1]
sell[I]只取决于buy[i-1],sell[i-1]. ,所以只用两个前置值就可以存储,所需要的空间复杂度为:O(1)
初始状态就是:buy=INT_MIN,sell=0,buy_prev=0,sell_prev=0;
代码如下:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int buy=INT_MIN, buy_prev=0,sell=0,sell_prev=0;
        for(int price:prices)
        {
            buy_prev=buy;
            buy=max(sell_prev-price,buy);
            sell_prev=sell;
            sell=max(buy_prev+price,sell);
        }
        return sell;
    }
};

接下来,说两道想类似的Best time to sell stock的问题,重点不是题目本身而是题目延伸出来的题目。
一是。121.Best Time to Buy and Sell Stock
Say you have an array for which the ith element is the price of a given stock on day i.

If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Example 1:
Input: [7, 1, 5, 3, 6, 4]
Output: 5

max. difference = 6-1 = 5 (not 7-1 = 6, as selling price needs to be larger than buying price)
Example 2:
Input: [7, 6, 4, 3, 1]
Output: 0

In this case, no transaction is done, i.e. max profit = 0.

这道题要求求出一个数组的后面一个数减去前面一个数的最大值。
最简单的二重循环暴力,时间复杂度O(n 2 )
正常做法就是:

for i=1:n
    Minbuy=min(Minbuy,prices[i])
    MaxPro=max(MaxPro,prices[I]-Minbuy)
end for

该问题实际上是寻找最大子串或者最小子串的问题,该问题使用的算法是Kadane’s Algorithm,一下给下链接:https://kartikkukreja.wordpress.com/2013/06/17/kadanes-algorithm/
比较好玩的是,下面提到的一个变形问题的内容:
如果给予的数组是经过差分的递减序列呢,所谓差分就是:A[i]-A[i-1],
例如:正常数组是:{1, 7, 4, 11},它的差分数组为:{0, 6, -3, 7}
那么,这个问题的解决方法当然是利用差分,diff[i]+diff[i-1]就代表从i-2到i的累积利润,那么就可以得到目前的累积利润值为:

CurPro+=diff[i]+diff[i-1]

代码如下:

    public int maxProfit(int[] prices) {
        int maxCur = 0, maxSoFar = 0;
        for(int i = 1; i < prices.length; i++) {
            maxCur = Math.max(0, maxCur += prices[i] - prices[i-1]);
            maxSoFar = Math.max(maxCur, maxSoFar);
        }
        return maxSoFar;
    }

最后,再说一道第一道题的简化题
122. Best Time to Buy and Sell Stock II
Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
给一串有着每天价格的商品,你可以尽可能的交易多次,得到最大收益
这道题同样可以根据第一题的动归思路,该序列的最后状态只有两种,一是buy,二是sell
那么最简单的递推公式为:

buy[i]=max(sell[i-1]-prices[i],buy[i-1])
sell[I]=max(buy[i-1]+prices[I],buy[i-1])

有一种更简单的思路,就是利用贪婪,只要能获利就尽可能获利,原理如下:
贪心算法,需要在每次能获利的时候都尽可能获利
举个例子,3,9,5。那么最好的情况就是9-3
3,1,5。那么最好情况就是5-1
3,4,5,最好的情况是5-3,但是在(5-4)+(4-3)也可以达到最大的收益,正是因为即使在递增的序列上,也能符合最好的情况

for I=1:n
    if(prices[I]>prices[I-1]) maxPro+=(prices[I]-prices[I-1])
end for
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值