leetcode-买卖股票的时机2

这篇博客讨论了如何使用动态规划算法解决寻找股票中最大利润的问题。通过分析交易人的两种状态——持有股票和不持有股票,建立了状态转移方程,即dp[i][0]=max(dp[i-1][0], dp[i-1][1]+prices[i])和dp[i][1]=max(dp[i-1][1], dp[i-1][0]-prices[i])。通过这种方式,可以有效地避免暴力搜索导致的时间复杂度过高,从而得到最大利润。

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

题目描述

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

示例 1:

输入: prices = [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
     随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。

示例 2:

输入: prices = [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
     注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例 3:

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

提示:

1 <= prices.length <= 3 * 104
0 <= prices[i] <= 104

思路

这里我们需要注意交易人有两种状态

  • 手里已经有一支股票了,根据题目意思,他之后进行的操作只能是卖出这支股票
  • 手里没有股票,那么他之后的操作就是选择一支股票卖出去

根据这两种情况,我们可以写出两种方案:

  • 暴力搜索
  • 动态规划

我们知道,动态规划就是为了避免多余的操作的,我们在进行暴力搜索的时候有些情况进行了多次,而动态规划其实就是要将这些重复的操作结果记录下来,以便下次直接使用。

暴力搜索

以[1,2,3,4]为例,下面是暴力搜索的树形图
在这里插入图片描述
我们要注意设置状态的判别

  • 如果手里有股票,我们得选择一个时间点卖出去,相应的收入就增加了price[i]
  • 如果手里没有股票,则需要选择一个时间点买入,相应的收入就减少了price[i]

代码如下:

class Solution {
    int max=0;
    public int maxProfit(int[] prices) {
        //选择买与卖
        int len = prices.length;
        if(prices.length<2){
            return max;
        }
        //用dfs
        dfs(0,prices, 1,0);
        return max;
    }

    public void dfs(int cur,int prices[],int flag,int sum){
        if(cur>prices.length){
            return;
        }
        if(cur==prices.length){
            if(sum>max){
                max=sum;
            }
            return;
        }
        dfs(cur+1,prices,flag,sum);//向前移动
        //手里已经有一个股票了,得选择卖出去
        if(flag==0){
            dfs(cur+1,prices,1,sum+prices[cur]);
        }else if(flag==1){
            //手里没得股票,得买一个
            dfs(cur+1,prices,0,sum-prices[cur]);
        }
    }
}

但是这种方法是超时的,因为数量量比较大。

动态规划

动态规划主要是找到状态转移方程,我们可以根据交易人的状态来进行设置。
我们可以定义一个数组dp[i][j]表示在第i个时间点交易人处于第j种状态时的最大收益。这里我们只有两种状态,则j=0或者1
dp[i][0]表示交易人手里没有股票,dp[i][1]表示交易人里面有股票
dp[i][0]的值取决于上一个时间点,如果是上一个时间点卖的股票,则值为上一个时间点有股票的利益最大值加上卖出这张股票后的和;如果在更早之前买了,就等于上一个时间点没有股票时的利益最大值。然后取这两种最大值。
dp[i][1]与此类似。
相应的,我们可以写出状态转移方程:

dp[i][0]=max(dp[i-1][0],dp[i-1][1]+price[i]);
dp[i][1]=max(dp[i-1][1],dp[i-1][0]-price[i]);

我们也要注意初始值,dp[0][0]=0
dp[0][1]=-prices[0],因为买了这一支股票

代码:

class Solution {
    public int maxProfit(int[] prices) {
        //选择买与卖
        int len = prices.length;
        //dp[i][0]与dp[i][1]
        //dp[i][0]表示第i支股票时已经卖出股票后利益的最大值
        //dp[i][1]表示第i支股票时没有卖出股票后利益的最大值
        int dp[][] = new int[len][2];
        dp[0][0]=0;
        dp[0][1]=-prices[0];
        for(int i=1;i<len;i++){
            dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);
            dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]-prices[i]);
        }
        return dp[len-1][0];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lzl2040

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值