leetcode 121、122、123、188、309、714 买卖股票的最佳时机

题目描述:
给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)即每个时刻只能有一股

各个题目的区别:
121——买卖一次
122——买卖无数次
123——最多买卖两次
188——买卖k次
309——有冷冻期,但是可以买卖无数次
714——每买卖一次有手续费,但是可以买卖无数次

思路:
动态规划,不同难度的问题,dp状态定义的维度和状态转移方程也是不一样的。
注意以下代码都是为了系统地比较各个问题的区别,可能每一段代码都可以进一步简化空间复杂度,但是dp的思路都是一样的。
121——买卖一次
dp[i]:到了第i 天的最大利润

class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        if not prices:
            return 0
        res = 0
        # 注意初始化的方式
        proit = [[0 for i in range(3)] for i in range(len(prices))]
        print(proit)
        proit[0][0], proit[0][1], proit[0][2] = 0, -prices[0], 0
        for d in range(1, len(prices)):
            # 三个状态分别是:没有买卖,已经买入一股,已经卖出一股
            proit[d][0] = proit[d-1][0]
            proit[d][1] = max(proit[d-1][1], proit[d-1][0] - prices[d])
            proit[d][2] = proit[d-1][1] + prices[d]
            res = max(res, proit[d][0], proit[d][1], proit[d][2])
        return res

122——买卖无数次:
dp[i][0]: 到了第i 天的最大利润,且此时手里没有股票,故可以选择买和不买
dp[i][1]:到了第i 天的最大利润,且此时手里有股票,故可以选择卖或者不卖

class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        res = 0
        proit = [[0 for i in range(2)] for i in range(len(prices))]
        proit[0][0], proit[0][1] = 0, -prices[0]
        for d in range(1, len(prices)):
        # m每次可以考虑买和卖两种情况
            proit[d][0] = max(proit[d-1][0], proit[d-1][1] + prices[d])
            proit[d][1] = max(proit[d-1][1], proit[d-1][0] - prices[d])
            res = max(res, proit[d][0])
        return res

123——最多买卖两次
dp[i][k][0] : 第i 天的利润,此时已经完成交易 k 次,手里没有股票
dp[i][k][0] : 第i 天的利润,此时已经完成交易 k 次,手里有股票
所以这里k有0,1,2三种可能情况,直接列举出来,这样减少一轮循环;
同样本题可以采用188的代码,将K设置为2。

import sys
maxint = sys.maxsize


class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        res = 0
        proit = [[[0 for i in range(2)] for i in range(3)] for i in range(len(prices))]
        proit[0][0][0], proit[0][0][1] = 0, -prices[0]
        proit[0][1][0], proit[0][1][1] = -maxint, -maxint
        proit[0][2][0], proit[0][2][1] = -maxint, -maxint
        for d in range(1, len(prices)):
            proit[d][0][0] = proit[d-1][0][0]
            proit[d][0][1] = max(proit[d-1][0][1], -prices[d])
            proit[d][1][0] = max(proit[d-1][1][0], proit[d-1][0][1] + prices[d])
            proit[d][1][1] = max(proit[d-1][1][1], proit[d-1][1][0] - prices[d])
            proit[d][2][0] = max(proit[d-1][2][0], proit[d-1][1][1] + prices[d])
            proit[d][2][1] = max(proit[d-1][2][1], proit[d-1][2][0] - prices[d])
            res = max(res, proit[d][0][0], proit[d][1][0], proit[d][2][0])
        return res

188——买卖k次
dp[i][k][0] : 第i 天的利润,此时已经完成交易 k 次,手里没有股票
dp[i][k][0] : 第i 天的利润,此时已经完成交易 k 次,手里有股票

import sys
maxint = sys.maxsize


class Solution(object):
    def maxProfit(self, k, prices):
        """
        :type k: int
        :type prices: List[int]
        :rtype: int
        """
        if not prices:
            return 0
        res = 0
        proit = [[[0 for i in range(2)] for i in range(k+1)] for i in range(len(prices))]
        proit[0][0][0], proit[0][0][1] = 0, -prices[0]
        for j in range(1, k):
            proit[0][j][0], proit[0][j][1] = -maxint, -maxint
        for d in range(1, len(prices)):
            proit[d][0][0] = proit[d-1][0][0]
            proit[d][0][1] = max(proit[d-1][0][1], -prices[d])
            for w in range(1, k+1):
                proit[d][w][0] = max(proit[d-1][w][0], proit[d-1][w-1][1] + prices[d])
                proit[d][w][1] = max(proit[d-1][w][1], proit[d-1][w][0] - prices[d])
                res = max(res, proit[d][w][0], proit[d][0][0])
        return res

309——有冷冻期,但是可以买卖无数粗
状态定义和转移详见代码

import sys
maxint = sys.maxsize

class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        if not prices or len(prices) == 1:
            return 0
        res = 0
        proit = [[0 for i in range(3)] for i in range(len(prices))]
        '''
        每天会有两种状态,持有和不持有,但是由于存在冷冻期,将不持有的情况分为两种:
        1. 会导致第二天冷冻期
        2. 不会导致第二天冷冻期
        '''
        proit[0][0], proit[0][1], proit[0][2] = 0, -prices[0], -maxint
        # 1-持有一股 0-不持有,不会导致第二天处于冷冻期 2-不持有,会导致第二天处于冷冻期
        for d in range(1, len(prices)):
            proit[d][1] = max(proit[d-1][1], proit[d-1][0]-prices[d])
            proit[d][0] = max(proit[d-1][0], proit[d-1][2])
            proit[d][2] = proit[d-1][1]+prices[d]
        res = max(res, proit[d][0], proit[d][2])
        return res

714——每买卖一次有手续费,但是可以买卖无数次
同122很像,只是多了一个手续费,体现在状态转移方程那里。

import sys
maxint = sys.maxsize


class Solution(object):
    def maxProfit(self, prices, fee):
        """
        :type prices: List[int]
        :type fee: int
        :rtype: int
        """
        if not prices or len(prices) == 1:
            return 0
        res = 0
        proit = [[0 for i in range(2)]for i in range(len(prices))]
        proit[0][0], proit[0][1] = 0, -prices[0]
        for d in range(1, len(prices)):
            proit[d][0] = max(proit[d-1][0], proit[d-1][1]+prices[d]-fee)
            proit[d][1] = max(proit[d-1][1], proit[d-1][0]-prices[d])
            res = max(res, proit[d][0], proit[0][0], proit[d][1])
        return res

扩展:
在现在的研究问题中,每个时刻只能持有一股,若题目变成可以持有n股,则:
dp[i][k][j]: j 从{0,1}变成0~j,此时状态转移:
dp[i][k][j] = max{
dp[i-1][k][j]; 不动
dp[i-1][k-1][j+1]+q[i]; 卖
dp[]i-1][k][j-1] - q[i]; 买
}
这时状态转移变得复杂,需要注意数组越界问题等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值