LeetCode刷题笔记—买卖股票的最佳时机Ⅰ~Ⅲ

一次搞定所有的买卖股票问题!!

买卖股票的最佳时机Ⅰ

原题地址:买卖股票的最佳时机Ⅰ

题目描述:

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

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

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

示例1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

思路:

1.dp数组的构建

考虑使用动态规划来完成,首先进行dp数组的构建,即数组里需要存储的数字代表的含义,由于只有买入之后才能卖出,那么可以将数组的长度设置为1,然后在遍历数组的过程中只存储股票最小的价格。在每次遍历时,先判断当天价格是否小于dp数组中的值,若小于,则买入,然后继续循环;若大于,则计算卖出之后的利润是否大于历史利润的最大值,若大于,则保存当前利润,否则,继续循环;若等于,继续循环。

2.状态转移方程
d p [ 0 ] = m i n ( d p [ 0 ] , p r i c e s [ i ] ) dp[0] = min(dp[0], prices[i]) dp[0]=min(dp[0],prices[i])

代码如下:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
    	dp = [prices[0]]
    	max_Profit = 0
    	for i in range(len(prices)):
    		dp[0] = min(dp[0], prices[i])
    		max_Profit = max(max_Profit, prices[i]-dp[0])
    	return max_Profit

买卖股票的最佳时机Ⅱ

原题地址:买卖股票的最佳时机Ⅱ

题目描述:

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

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

返回 你能获得的 最大 利润 。

示例1:

输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
     随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
     总利润为 4 + 3 = 7 。

示例2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
     总利润为 4 。

示例3:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。

思路:

相对于第一种情况而言,改变的只有交易次数,从限制1次变为无数次。在没有交易限制的情况下,只要有利可图,我们就出手。因此,考虑贪心算法解决上述问题。开始遍历数组,并取数组中的第一个元素作为最小值,在遍历过程中,如果当前列表中的元素比最小值小,最小值等于当前元素;若大于,则相当于卖出股票,计算获得利润并累加至总利润中;若等于,循环继续。

考虑如下情况,可以简化计算过程:

有三个数,大小分别为大,中,小

当排列顺序为大,中,小时,最大利润为0

当排列顺序为大,小,中时,最大利润为0

当排列顺序为小,中,大时,最大利润为中 - 小 + 大 - 中,即:
p r i c e s [ 1 ] − p r i c e s [ 0 ] + p r i c e s [ 2 ] − p r i c e s [ 1 ] prices[1] - prices[0] + prices[2] - prices[1] prices[1]prices[0]+prices[2]prices[1]

当排列顺序为小,大,中时,最大利润为大 - 小,即:
p r i c e s [ 1 ] − p r i c e s [ 0 ] prices[1] - prices[0] prices[1]prices[0]

当排列顺序为中,大,小时,最大利润为大 - 中,即:
p r i c e s [ 1 ] − p r i c e s [ 0 ] prices[1] - prices[0] prices[1]prices[0]

当排列顺序为中,小,大时,最大利润为大 - 小,即:
p r i c e s [ 2 ] − p r i c e s [ 1 ] prices[2] - prices[1] prices[2]prices[1]

可将上述情况化简如下:

首先判断 p r i c e s [ i + 1 ] − p r i c e s [ i ] prices[i+1] - prices[i] prices[i+1]prices[i]是否大于0,若大于, 总利润 + p r i c e s [ i + 1 ] − p r i c e s [ i ] 总利润+prices[i+1] - prices[i] 总利润+prices[i+1]prices[i]否则,继续循环列表

代码如下:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        all_Profit = 0
        for i in range(len(prices)-1):
            if prices[i+1] - prices[i] > 0:
                all_Profit += prices[i+1] - prices[i]
        return all_Profit

买卖股票的最佳时机Ⅲ

原题地址:买卖股票的最佳时机Ⅲ

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

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

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

示例1:

输入:prices = [3,3,5,0,0,3,1,4]
输出:6
解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
     随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。

示例2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。   
     注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。   
     因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例3:

输入:prices = [7,6,4,3,1] 
输出:0 
解释:在这个情况下, 没有交易完成, 所以最大利润为 0。

示例4:

输入:prices = [1]
输出:0

思路:

当开始限制交易次数后,动态规划便成为最优解决方案。相对于第一种情况来说,就需要采取更为复杂的dp数组。

首先,由示例4,我们需要考虑列表中只有1种元素或者没有元素的情况。

if len(prices) <= 1:
	return 0

1.dp数组的构建

首先根据买入和卖出两种操作方式,可以建立两个dp数组记录操作过程。设记录买入的情况为dp0列表,有记录卖出的情况为dp1列表。由此,列表的长度为交易的次数+1(从K=1开始循环,因为之后会用到K-1,K为交易次数)。dp数组的元素含义为截止到第K次交易时的总利润。

初始化:

对于dp0来说,刚开始并没有买入任何一支股票,因此0初始化即可

对于dp1来说,刚开始可以先买入第一天的股票,因此prices[0]初始化即可

2.状态转移方程

对于dp0列表,即买入的情况来说:

是否更新第K次买入的最大利润,取决于以下两种情况的最大值

(1)不更新,仍然维持原第K次买入的利润,即 d p 0 [ k ] dp0[k] dp0[k]

(2)进行更新,利润变为原K-1次卖出再减去当天股票的价格,即 d p 1 [ k − 1 ] − p r i c e s [ i ] dp1[k-1] - prices[i] dp1[k1]prices[i]

考虑到本题要求最大利润,即对上述两种情况进行最大值计算,即为dp0数组的状态转移方程:

d p 0 [ k ] = m a x ( d p 0 [ k ] , d p 1 [ k − 1 ] − p r i c e s [ i ] ) dp0[k] = max(dp0[k], dp1[k-1] - prices[i]) dp0[k]=max(dp0[k],dp1[k1]prices[i])

对于dp1列表,即买入的情况来说:

是否更新第K次卖出的最大利润,取决于以下两种情况的最大值

(1)不更新,仍然维持原第K次卖出的利润,即 d p 1 [ k ] dp1[k] dp1[k]

(2)进行更新,利润变为原K次买入再加上当天股票的价格,即 d p 0 [ k ] + p r i c e s [ i ] dp0[k] + prices[i] dp0[k]+prices[i]

考虑到本题要求最大利润,即对上述两种情况进行最大值计算,即为dp1数组的状态转移方程:

d p 1 [ k ] = m a x ( d p 1 [ k ] , d p 0 [ k ] + p r i c e s [ i ] ) dp1[k] = max(dp1[k], dp0[k] + prices[i]) dp1[k]=max(dp1[k],dp0[k]+prices[i])

当交易2次后结束循环,最后我们返回 d p 1 [ 2 ] dp1[2] dp1[2]即可

代码如下:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if len(prices) < 2:
            return 0
        
        dp0 = [-prices[0]] * (2 + 1)
        dp1 = [0] * (2 + 1)

        for i in range(1, len(prices)):
            for j in range(1, 2+1):
                dp0[j] = max(dp0[j], dp1[j-1] - prices[i])
                dp1[j] = max(dp1[j], dp0[j] + prices[i])
        
        return max(dp1[2], 0)

完结撒花~~~~~~~~~~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值