leetcode 121,122

本文介绍了三种算法解决股票买卖的最佳时机问题,包括只允许进行一次交易的情况和允许进行多次交易的情况。通过具体示例展示了如何寻找最大利润。

121Best 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 (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Note that you cannot sell a stock before you buy one.

Example 1:

Input: [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 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
Explanation: In this case, no transaction is done, i.e. max profit = 0.

数组是股票价格 股票买卖低价买之后高价卖求最大利润

方法一    第一层循环是卖出时间 第二次循环是买入时间 当买入价格<卖出时计算利润并看是否最大

class Solution {
    public int maxProfit(int[] prices) {
       int max=0;
       
        for(int sall=prices.length-1;sall>0;sall--)
        {
            for(int buy=sall-1;buy>=0;buy--)
            {
                if(prices[buy]<prices[sall])
                {
                    int profit = prices[sall] - prices[buy];
                    max=Math.max(max,profit);
                }
               
                
            }
        }
        return max;
    }
}

方法2   

class Solution {
    public int maxProfit(int[] prices) {
        if (prices.length == 0) {
			 return 0 ;
		 }
        int max=0;
       int curmin=prices[0];//当前最小数字
        for(int i=1;i<prices.length;i++)
        {
            if(prices[i]>curmin)
            {
                max=Math.max(max,prices[i]-curmin);
            }
            else
            {
                curmin=prices[i];
            }
        }
       
        return max;
    }
}

方法 3 

      Kadane's Algorithm,专门来求最大子序列的和,算法就是考虑,数组中的A[I]前面的的序列段的和为sum,如果sum大于等于零,那么加上A[i],如果sum小于零,就没有必要加了,不如直接保留A[i],这样就相当于从A[i]开始的一个新的数字段。保留一个max保存最大的值,每次都和max比较。

7,1,5,3,6,4   的最大利润     相当于求 0,-6,4,-2,3,-2; 最大子序列的和

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

122Best 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 (i.e., buy one and sell one share of the stock multiple times).

Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).

Example 1:

Input: [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
             Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.

Example 2:

Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
             Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
             engaging multiple transactions at the same time. You must sell before buying again.

Example 3:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

在上题的基础上可多次买卖股票

class Solution {
    public int maxProfit(int[] prices) {
        if(prices.length==0) return 0;
        int curmin=prices[0];
        int profit=0;
        for(int i=1;i<prices.length;i++)
        {
            if(prices[i]>curmin)
            {
                profit+=prices[i]-curmin;
                
            }
            curmin=prices[i];
        }
        return profit;
    }
}


<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]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值