力扣题解-121. 买卖股票的最佳时机(动态规划)

题目:121. 买卖股票的最佳时机

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。

注意:你不能在买入股票前卖出股票。

示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

分析

由于只允许完成一次交易(买入和卖出),因此直接穷举遍历每一种可能的交易,然后求出所有交易的最大利润。

具体的以[7,1,5,3,6,4]为例,遍历所有可能执行卖出的天数(第一天不能卖出),然后找出价格最低的买入天数,即可得到最大利润:

执行卖出的天数i价格最低的买入天数j最大利润prices[i]-prices[j]
211 - 7 = -6
325 - 1 = 4
423 - 1 = 2
526 - 1 = 5
624 - 1 = 3

这里需要两层循环。第一层循环遍历所有的卖出天数i,第二层循环查找前i天内价格最低的天数j,最大利润为prices[i]-prices[j]

由于需要两层循环,上述方法时间复杂度为 Θ ( n 2 ) \Theta(n^2) Θ(n2)

由于只用到循环变量和一个变量存储最大利润,则空间复杂度为 Θ ( 1 ) \Theta(1) Θ(1)

动态规划

利用动态规划的思想来降低时间复杂度。

可以看到,上述分析中,第二层循环查找的是前i天内价格最低的天数。

状态定义

n = p r i c e s . s i z e ( ) n = prices.size() n=prices.size()

定义 d p 1 [ 0 , 1 , ⋯   , n − 1 ] dp1[0,1,\cdots,n-1] dp1[0,1,,n1] d p 1 [ i ] dp1[i] dp1[i]表示前 i i i天的最低价格。

定义 d p 2 [ 0 , 1 , ⋯   , n − 1 ] dp2[0,1,\cdots,n-1] dp2[0,1,,n1] d p 2 [ i ] dp2[i] dp2[i]表示第 i i i天卖出时获取的最大利润。

转移方程

d p 1 [ i ] = m i n ( d p 1 [ i − 1 ] , p r i c e s [ i ] ) dp1[i] = min(dp1[i-1], prices[i]) dp1[i]=min(dp1[i1],prices[i])

d p 2 [ i ] = p r i c e s [ i ] − d p 1 [ i − 1 ] dp2[i] = prices[i] - dp1[i-1] dp2[i]=prices[i]dp1[i1]

边界条件

d p 1 [ 0 ] = p r i c e s [ 0 ] dp1[0] = prices[0] dp1[0]=prices[0]

d p 2 [ 0 ] = 0 dp2[0] = 0 dp2[0]=0

最优解

a n s = m a x ( d p 2 [ i ] ) , i = 0 , 1 , 2 , ⋯   , n − 1 ans = max(dp2[i]),i=0,1,2,\cdots,n-1 ans=max(dp2[i])i=0,1,2,,n1

复杂度分析

由于只有一个循环变量,因此只需要遍历一次即可,时间复杂度为 Θ ( n ) \Theta(n) Θ(n)

申请了两个长度为 n n n的数组 d p 1 , d p 2 dp1, dp2 dp1,dp2,空间复杂度为 Θ ( n ) \Theta(n) Θ(n)

动态规划实现了以空间换时间的思想。

空间复杂度的改进

分析状态转移方程可以发现,状态 d p 1 [ i ] dp1[i] dp1[i] d p 2 [ i ] dp2[i] dp2[i]只与前一个状态和当前循环变量 p r i c e s [ i ] prices[i] prices[i]有关。

因此,可以进一步降低空间复杂度到 Θ ( 1 ) \Theta(1) Θ(1)级别。

代码

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        if (n == 0) {
            return 0;
        }
        int ans = 0;//第i天卖出时的最大利润
        int low = prices[0];//前i-1天的最低价格
        for (int i = 1; i < prices.size(); i++) {
            ans = max(ans, prices[i] - low);
            low = min(low, prices[i]);
        }
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值