LeetCode 121、122、123 买卖股票

LeetCode 121 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0

提示:

  • 1 <= prices.length <= 10^5
  • 0 <= prices[i] <= 10^4

问题分析

动态规划,子问题就是找子数组的最大利润dp[i],而最大利润可以用前一个子数组的最大利润与当前价格-当前买入价格(最小价格) 进行对比得出,因为只有当当前价格比之前更高时,才有希望得到比之前更高的利润。前一个子数组的最大利润为dp[i-1],当前价格为prices[i],当前买入价格为cost = min(cost,prices[i]),状态转移方程如下:
d p [ i ] = m a x ( d p [ i − 1 ] , p r i c e s [ i ] − m i n ( c o s t , p r i c e s [ i ] ) ) dp[i]=max(dp[i-1],prices[i]-min(cost,prices[i])) dp[i]=max(dp[i1],prices[i]min(cost,prices[i]))
这里实现需要注意的是:

  1. 这里使用了变量cost存储买入价格选择,避免了每次遍历数组寻找最小值,降低时间复杂度;
  2. 在迭代更新dp[i]cost应是当前的最小价格,故应先更新cost
  3. 状态转移方程中包含了dp[i-1],这使得循环应从i=1开始,需单独考虑n==1时的返回值;
  4. 由于循环从i=1开始,cost的初始值应为prices[0]
class Solution {
    public int maxProfit(int[] prices) {
        // dp[i]=max(dp[i-1],prices[i]-min(cost,prices[i]))
        int n = prices.length, cost = prices[0];
        if(n==1) return 0;
        int []dp = new int[n];
        for(int i=1;i<n;i++){
            cost = Math.min(cost,prices[i]);
            dp[i]=Math.max(dp[i-1],prices[i]-cost);
        }
        return dp[n-1];

    }
}

优化空间复杂度

滚动数组,观察可知,dp[i]只与前面的dp[i-1]有关,其余prices[i]为需要遍历的对象——当前价格,cost为当前买入价格,故可使用单个变量profit替换掉dp数组,这样还可以避免循环中的索引使用
p r o f i t = m a x ( p r o f i t , p r i c e − m i n ( c o s t , p r i c e ) ) profit=max(profit,price-min(cost,price)) profit=max(profit,pricemin(cost,price))

class Solution {
    public int maxProfit(int[] prices) {
        // 滚动数组 profit = max(profit,price - min(cost,price))
        int profit=0, cost = Integer.MAX_VALUE;
        for(int price:prices){
            cost = Math.min(cost,price);
            profit = Math.max(profit,price - cost);
        }
        return profit;
    }
}

LeetCode 122 买卖股票的最佳时机 II

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润
提示:

  • 1 <= prices.length <= 3 * 10^4
  • 0 <= prices[i] <= 10^4
class Solution {
    public int maxProfit(int[] prices) {
        if(prices.length==1) return 0;
        int ans=0;
        for(int i=1;i<prices.length;i++)
        {
            if(prices[i]>prices[i-1])
            {
                ans+= prices[i]-prices[i-1];
            }
        }
        return ans;

    }
}
class Solution {
    public int maxProfit(int[] prices) {
        if(prices.length==1) return 0;
        int profit_0 = 0, profit_1 = -prices[0];
        for(int i=1;i<prices.length;i++)
        {
            profit_0 = Math.max(profit_0,profit_1+prices[i]);
            profit_1 = Math.max(profit_1,profit_0-prices[i]);
            //profit_1<profit_1+prices[i],profit_0-prices[i]<profit_0,最后一定是profit_0大
        }
        return profit_0;
}
}

LeetCode 123 买卖股票的最佳时机III

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

设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。

**注意:**你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

提示:

  • 1 <= prices.length <= 10^5
  • 0 <= prices[i] <= 10^5
class Solution {

    public int maxProfit(int[] prices) {

        int n = prices.length;

        if(n==1) return 0;

        int dp10 = -prices[0], dp01 = 0, dp11 = -prices[0], dp02 = 0;

        //同一天可以买入卖出再买入

        for(int i=1;i<n;i++)

        {

            // dp[i][1][0] = Math.max(dp[i-1][1][0],-prices[i]);

            // dp[i][0][1] = Math.max(dp[i-1][0][1],dp[i-1][1][0]+prices[i]);

            // dp[i][1][1] = Math.max(dp[i-1][1][1],dp[i-1][0][1]-prices[i]);

            // dp[i][0][2] = Math.max(dp[i-1][0][2],dp[i-1][1][1]+prices[i]);

  

            // dp[i][1][0] = Math.max(dp[i-1][1][0],-prices[i]);

            // dp[i][0][1] = Math.max(dp[i-1][0][1],dp[i][1][0]+prices[i]);

            // dp[i][1][1] = Math.max(dp[i-1][1][1],dp[i][0][1]-prices[i]);

            // dp[i][0][2] = Math.max(dp[i-1][0][2],dp[i][1][1]+prices[i]);

            dp10 = Math.max(dp10,-prices[i]);

            dp01 = Math.max(dp01,dp10+prices[i]);

            dp11 = Math.max(dp11,dp01-prices[i]);

            dp02 = Math.max(dp02,dp11+prices[i]);

        }

  

        return dp02;

  
  

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值