[Leetcode] 121. Best Time to Buy and Sell Stock

博客围绕给定数组求股票买卖最大利润问题展开。先描述问题,即给定股价数组,求买卖一次的最大利润。接着介绍用动态规划算法求解,通过逐步扩大问题规模,推导不同规模问题解之间的关系。最后指出可优化空间复杂度,不使用一维数组,用变量保存最大值。

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

题目描述

给定一个数组prices, prices[i]表示第i天股票的股价,现在你可以在某一天买一次股票,在后面的另外一天再把股票卖了,那么中间的差价prices[j]-proces[i]就是你赚取的利润,求你能赚的利润的最大值。
举个例子

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.

分析思路

这种题应该用动态规划(dynamic planning,dp算法)做。动态规划就是求源问题规模较小时的情况,慢慢扩大规模,逐步求解。在上面的例子里,prices=[7,1,5,3,6,4],这是原问题的规模,那么比它规模较小的那个问题应该是prices=[7,1,5,3,6],并且[7,1,5,3,6,4]的求解依赖于[7,1,5,3,6],依次类推,推到最小的问题规模[7,1],因为数组最起码要有两个元素。

当[7,1]时,最大利润很明显=0
当[7,1,5]时,最大规模=5-1=4
当[7,1,5,3]时,最大规模=5-1=4
。。。
那么每种规模问题的解之间存在什么关系呢?

先定义几个表示方式。[7,1]时的问题的解,我们定义为dp[2],[7,1,5]的解,定义为dp[3],依次类推。

那么怎么根据dp[3]之前的解推导出dp[3],是动态规划最核心的问题。

这里dp[3]表示,数组长度为3时,买卖股票的最大利润。
按常识,dp[3] = max(dp[2], prices[2]-minPrice),这里的prices[2]表示第3天的股价。

按照这个公式,我们推一下。

先确定初始条件,dp[0]=dp[1]=0,当数组长度小于2时,利润为0。

dp[2]: [7,1]的时候,dp[2] = max(dp[1], prices[1]-minPrice) = max(0, 1-7) = 0;
dp[3]: [7,1,5]的时候,dp[3] = max(dp[2], prices[2]-minPrice) = max(0, 5-1) = 4;
dp[4]: [7,1,5,3]的时候,dp[4] = max(dp[3], prices[3]-minPrice) = max(4, 3-1) = 4;
dp[5]: [7,1,5,3,6]的时候,dp[5] = max(dp[4], prices[4]-minPrice) = max(4, 6-1) = 5;
dp[6]: [7,1,5,3,6,4]的时候,dp[6] = max(dp[5], prices[5]-minPrice) = max(5, 4-1) = 5;

代码

class Solution {
    public int maxProfit(int[] prices) {
        if (prices.length < 2){
            return 0;
        }
        int currentMin = prices[0];
        int[] dp = new int[prices.length+1]; //dp[i] = 0,初始化全部为0
        for (int i = 2; i <= prices.length; i++){
            dp[i] = Math.max(dp[i-1], prices[i-1]-currentMin);
            currentMin = Math.min(currentMin, prices[i-1]);
        }
        return dp[prices.length];
    }
}

优化的地方

在上面的例子里,我们维护了一个一维数组,空间复杂度为O(n),但是在实际的编码过程中,我们在求dp[i]的时候,依赖的那个dp[i-1]一定是前面所有dp[j], j<i的最大值。因此,我们可以不使用这样的一维数组,而仅仅使用一个变量来保存已经求得的dp中的最大值即可。

class Solution {
    public int maxProfit(int[] prices) {
        if (prices.length < 2){
            return 0;
        }
        int currentMaxProfit = 0;
        int currentMin = prices[0];
        for (int i = 0; i < prices.length; i++) {
            currentMin = Math.min(currentMin, prices[i]);
            currentMaxProfit = Math.max(currentMaxProfit, prices[i]-currentMin);
        }
        return currentMaxProfit;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值