动态规划算法-简单多状态dp问题:16.买卖股票的最佳时机含手续费

AgenticCoding·十二月创作之星挑战赛 10w+人浏览 155人参与

题目链接:714. 买卖股票的最佳时机含手续费(中等)

算法原理:

解法:动态规划

Java代码:

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 王洋
 * Date: 2025-10-20
 * Time: 20:22
 */
class Solution {
    //714.买卖股票的最佳时机含手续费
    //看完算法原理后第二天自己写的,一遍过
    //吴小哲跟我写的一样
    public int maxProfit(int[] prices, int fee) {
        int n=prices.length;
        int[] f=new int[n];
        int[] g=new int[n];
        f[0]=-prices[0];
        for(int i=1;i<n;i++){
            f[i]=Math.max(f[i-1],g[i-1]-prices[i]);
            g[i]=Math.max(g[i-1],f[i-1]+prices[i]-fee);
        }
        return g[n-1];
    }
}

<think>首先,用户的问题是:理解LeetCode121题的动态规划解法,并进行复杂度分析。题号是LeetCode121,题目是"买卖股票最佳时机",只能买卖一次。回顾引用:[1],[2],[3],[4],[5]都提到了这个问题。[4]和[5]特别提供了示例,比如输入[7,1,5,3,6,4]输出5,意思是在价格最低点买(第2天价格1),最高点卖(第5天价格6),获得最大利润5。动态规划解法:引用[2],[3],[5]讨论了动态规划。[3]提到122题可以多次买卖,121题只能买卖一次。[2]比较了贪心和动态规划动态规划更适合复杂规则。动态规划状态设计:对于121题,因为只能买卖一次,状态通常包括:-持有股票状态(买入后未卖)-不持有股票状态(未买入或已卖出)定义状态:-dp[i][0]表示第i天不持有股票时的最大利润-dp[i][1]表示第i天持有股票时的最大利润递推关系:-dp[i][0]的第i天不持有:要么是前一天就不持有(dp[i-1][0]),要么是前一天持有今天卖出(dp[i-1][1]+prices[i]),取最大值。-dp[i][1]的第i天持有:要么是前一天就持有(dp[i-1][1]),要么是今天买入(注意只能买入一次,所以买入时利润是-prices[i],因为买入消耗资金)。初始化:-第0天不持有:dp[0][0]=0-第0天持有:dp[0][1]=-prices[0]因为买入股票花了prices[0]最终结果:dp[n-1][0],因为最后一天不持有股票时利润最大(如果持有,不如卖出)。简化版:因为状态只依赖于前一天,空间可以优化成O(1)。复杂度:时间复杂度O(n),n是天数;空间O(1)如果优化。现在,用户要求算法设计和复杂度分析,所以需要结构清晰。按照系统指令:-数学表达式用美元符号,如dp[i][0]-独立公式用$$...$$-中文回答-生成相关问题-引用标识:[^引用号]回答结构:1.问题描述:简述LeetCode121问题2.动态规划设计:状态定义、递推公式、初始化、结果计算3.复杂度分析:时间和空间4.代码示例:用Python或其他语言实现(可选,但用户没说,参考引用中有)5.生成相关问题参考用户上次问题和我的回答:用户是第一次问,无上下文,所以直接回答。最后部分:添加相关问题,如引用示例的末尾。步骤:-先描述算法设计-然后复杂度-代码:既然引用中有,我可以提供伪代码或Python-相关问题代码:引用中没直接给121的完整代码,但可以写一个简单的。例如,参考[5]的示例。完整动态规划代码:defmaxProfit(prices):n=len(prices)ifn<=1:return0dp0=0#不持有dp1=-prices[0]#持有foriinrange(1,n):new_dp0=max(dp0,dp1+prices[i])new_dp1=max(dp1,-prices[i])#因为只能买卖一次,买入时是第一次dp0,dp1=new_dp0,new_dp1returndp0复杂度:O(n)时间,O(1)空间。问题设计:相关问题应基于引用,比如:-LeetCode122:多次买卖-优化方法?但121题简单-比较贪心和动态规划现在,编写响应。</think> ### LeetCode 121:买卖股票最佳时机动态规划解法与复杂度分析) LeetCode 121题“买卖股票最佳时机”要求设计算法,在给定股票价格数组(如`prices = [7,1,5,3,6,4]`)中,找到一次买入和卖出股票的最大利润(只能买卖一次)。例如,输入`[7,1,5,3,6,4]`输出`5`(第2天1元买入,第5天6元卖出)[^4][^5]。动态规划是解决此问题的核心方法,它能确保获得全局最优解,相比贪心算法更可靠(贪心可能无法处理所有情况)[^2]。 #### 动态规划算法设计 动态规划的核心是定义状态和状态转移方程。问题限制只能买卖一次,因此需跟踪“持有股票”和“不持有股票”两种状态: - **状态定义**: - `dp[i][0]`:表示第`i`天结束时**不持有股票**的最大利润。 - `dp[i][1]`:表示第`i`天结束时**持有股票**的最大利润。 其中,`i`是数组下标,从`0`到`n-1`(`n = len(prices)`)。 - **递推公式**: - **不持有股票状态**:第`i`天结束时,要么是前一天就不持有且今天无操作,要么是前一天持有今天卖出(卖出增加利润`prices[i]`): $$ \text{dp}[i][0] = \max(\text{dp}[i-1][0], \text{dp}[i-1][1] + \text{prices}[i]) $$ - **持有股票状态**:第`i`天结束时,要么是前一天就持有且今天无操作,要么是今天首次买入(注意只能买卖一次,买入消耗`prices[i]`,初始利润为负): $$ \text{dp}[i][1] = \max(\text{dp}[i-1][1], -\text{prices}[i]) $$ - **初始化**: - 第`0`天:不持有股票时利润为`0`(未买入),持有股票时需买入,利润为`-prices[0]`: $$ \text{dp}[0][0] = 0, \quad \text{dp}[0][1] = -\text{prices}[0] $$ - **结果计算**: 最大利润为最后一天不持有股票的状态(因为如果持有,卖出才能获利): $$ \text{maxProfit} = \text{dp}[n-1][0] $$ - **优化空间复杂度**:状态仅依赖前一天,可优化为两个变量(空间从 $O(n)$ 降为 $O(1)$)。 **Python实现**: ```python def maxProfit(prices): n = len(prices) if n <= 1: return 0 dp0 = 0 # 不持有股票的最大利润 dp1 = -prices[0] # 持有股票的最大利润 for i in range(1, n): new_dp0 = max(dp0, dp1 + prices[i]) # 更新不持有状态 new_dp1 = max(dp1, -prices[i]) # 更新持有状态(只允许一次买入) dp0, dp1 = new_dp0, new_dp1 # 滚动更新 return dp0 # 示例测试 prices = [7,1,5,3,6,4] print(maxProfit(prices)) # 输出: 5 ``` - **代码解读**: - 初始化`dp0=0`, `dp1=-prices[0]`对应第0天状态。 - 遍历数组,计算每个位置的不持有/持有状态。 - 最后返回`dp0`即最大利润。 #### 复杂度分析 - **时间复杂度**:$O(n)$,其中`n`是价格数组长度。算法仅需一次遍历计算状态,每次操作是常数时间。 - **空间复杂度**:$O(1)$,使用滚动变量代替二维数组,仅需常数空间。 动态规划在此问题中高效且直观,相比暴力法($O(n^2)$)显著优化[^4]。对于更复杂的股票问题(如多次交易或带手续费),动态规划可扩展性强[^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值