[Leetcode] 121, 122, 3

本文介绍了两种股票交易算法,一种适用于只能进行一次买卖的情况,另一种则不限制交易次数。通过寻找最佳买卖点来最大化利润,并提供了详细的算法思路及C++实现代码。

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.

Solution: 对于每个点,卖出它得到的最大收益都是在它之前的最小值买入时取得的,因此遍历的时候一边求最小值,一边计算收益即可。

Code:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int min = INT_MAX;
        int maxP = 0;
        for(int i=0; i<prices.size(); i++){
            if(min<prices[i]){
                maxP = max(prices[i]-min, maxP);
            }else{
                min = prices[i];
            }
        }
        return maxP;
    }
};



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).

Solution: 极小值买入,它之后的极大值卖出,对所有的极值点进行这个操作即可得到最佳收益。(我直接求了极值点,但是其实可以直接计算prices[i]-prices[i-1],然后累加所有的正值,这样求得的也是相等的结果。)

Code:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.size()<=1) return 0;
        int m = INT_MAX; //记录买下的价格, INT_MAX表示没有买
        int mp = 0; //记录总利润
        for(int i=0; i<prices.size()-1; i++){
            if(prices[i]>m && prices[i]>=prices[i+1]){
                mp += prices[i]-m;
                m = INT_MAX;
            }else if(prices[i]<m){
                m = prices[i];
            }
        }
        if(*(prices.end()-1)>m) mp+=*(prices.end()-1)-m;
        return mp;
    }
};



3. Longest Substring Without Repeating Characters


Given a string, find the length of the longest substring without repeating characters.

Examples:

Given "abcabcbb", the answer is "abc", which the length is 3.

Given "bbbbb", the answer is "b", with the length of 1.

Given "pwwkew", the answer is "wke", with the length of 3. Note that the answer must be a substring"pwke" is a subsequence and not a substring.

Solution: 对于每个字符,记录下最后一次出现的位置。对于新的字符,检查其上一次出现的位置,如果它在当前字符串内出现了,则将字符串起点重新设置为该字符的后一个位置。此外,因为前面的字符都已经检测过,确定当前字符串之内没有重复的字符,所以不需要重新遍历,只需要直接后移检测下一个新字符。


Code:

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        if(s.size()==0) return 0;
        int ans = 0;
        int cur = 0;
        int visited[256];//注意ASCII码总共有256个
        fill_n(visited, 256, -1);
        for(int i=0; s[i]; i++){
            int length = i - visited[s[i]];
            cur = min(cur+1, length);
            ans = max(cur, ans);
            visited[s[i]] = i;
        }
        return ans;
    }
};


<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、付费专栏及课程。

余额充值