LeetCode 188. Best Time to Buy and Sell Stock IV

简介: 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。

v2-c19a8d921a5ea54bf3e20d0d2645fabe_1440w.jpg

Description



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 at most k transactions.


Note:

You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).


Example 1:

Input: [2,4,1], k = 2

Output: 2

Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.


Example 2:

Input: [3,2,6,5,0,3], k = 2

Output: 7


Explanation: Buy on day 2 (price = 2) and sell on day 3 (price = 6), profit = 6-2 = 4.

Then buy on day 5 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.


描述



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

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


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


示例 1:

输入: [2,4,1], k = 2

输出: 2

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


示例 2:

输入: [3,2,6,5,0,3], k = 2

输出: 7


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

随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。


思路



  • 这道题使用动态规划.
  • 我们用一个二维矩阵trans,矩阵的列表示交易的价格,矩阵的行表示交易的次数,矩阵的值表示当前能够获得的最大利润.如上图所示,第一行表示进行0次交易,获得的利润为0;第一列表示在第一天(索引为0)进行交易,只有一天无法进行完整的交易,所以活力为0.
  • 以允许3次交易,第3天为例,trans[3][3],我们有如下的选择:
  • 1,在这一天我们什么什么都不做,于是我们获得昨天tans[3][2]的利润
  • 2.我们以今天的价格为卖出价,以第0天为买进价,则可以获得利润pri1 = pries[3]-prices[0](占用一次交易次数)+trans[2][0](截止第0天,交易2次获得最大利润)
  • 3.我们以今天的价格为卖出价,以第1天为买进价,则可以获得利润pri2 = pries[3]-prices[1](占用一次交易次数)+trans[2][1](截止第1天,交易2次获得最大利润)
  • 4.我们以今天的价格为卖出价,以第2天为买进价,则可以获得利润pri3 = pries[3]-prices[2](占用一次交易次数)+trans[2][2](截止第2天,交易2次获得最大利润)
  • 于是tans[3][3] = max(tans[3][2],pri1,pri2,pri3)
  • 同理tans[3][4]的最大值:
  • 1,在这一天我们什么什么都不做,于是我们获得昨天tans[3][3]的利润
  • 2.我们以今天的价格为卖出价,以第0天为买进价,则可以获得利润pri1 = pries[4]-prices[0](占用一次交易次数)+trans[2][0](截止第0天,交易2次获得最大利润)
  • 3.我们以今天的价格为卖出价,以第1天为买进价,则可以获得利润pri2 = pries[4]-prices[1](占用一次交易次数)+trans[2][1](截止第1天,交易2次获得最大利润)
  • 4.我们以今天的价格为卖出价,以第2天为买进价,则可以获得利润pri3 = pries[4]-prices[2](占用一次交易次数)+trans[2][2](截止第2天,交易2次获得最大利润)
  • 5.我们以今天的价格为卖出价,以第2天为买进价,则可以获得利润pri4 = pries[4]-prices[3](占用一次交易次数)+trans[2][3](截止第3天,交易2次获得最大利润)
  • 这样我们就可以求得第k次交易的最大值.
  • 我们将-prices[0](占用一次交易次数)+trans[2][0]记为P1,-prices[1](占用一次交易次数)+trans[2][1]记为P2,-prices[2](占用一次交易次数)+trans[2][2]记为P3
  • 时间复杂度O(n^3),我们发现观察上面的过程可以发现,在判断tans[3][3]的值的时候,其中P1,P2,P3,已经被计算过,而我们要求的值
  • tans[3][4]= max(tans[3][3],pries[4]+P1,pries[4]+P2,pries[4]+P3,pries[4]-prices[3](占用一次交易次数)+trans[2][3]).
  • tans[3][4]= max(tans[3][3],pries[4]+max(P1,P2,P3,-prices[3](占用一次交易次数)+trans[2][3])).
  • 于是我们可以首先计算max(P1,P2,P3,-prices[3](占用一次交易次数)+trans[2][3])=maxdiff,这样就可以减少一次循环.
  • 空间复杂度O(n^2),通过上面的描述发现,每次在被允许k次交易的时候,我们只需要知道第k-1次交易的信息,k-2,k-3已经不需要知道了,所以我们只用生成一个两行的矩阵即可.
  • 还需要注意的是,n天最多可以进行n/2取整次交易,当给定的交易次数k>=n/2时,题目相当于转换成了可以被允许进行无限次交易.


# -*- coding: utf-8 -*-
# @Author:             何睿
# @Create Date:        2019-01-19 12:53:32
# @Last Modified by:   何睿
# @Last Modified time: 2019-01-19 14:31:38
class Solution:
    def maxProfit(self, k, prices):
        """
        :type k: int
        :type prices: List[int]
        :rtype: int
        """
        #交易次数为0或者交易天数小于2时无法进行交易,返回0
        if len(prices) < 2 or k == 0:
            return 0
        # n天最多可以交易n//2次,当允许的交易次数大于这个天数的时候,这道题就转换
        # 成了不限制交易次数
        if k >= (len(prices) // 2):
            return sum(i - j for i, j in zip(prices[1:], prices[:-1]) if i - j > 0)
        # 生命矩阵,动态规划
        # 为了避免出现内存超出限制,根据本题的特点,矩阵只需要两行就够了
        row, col = 2, len(prices)
        trans = [[0 for _ in range(col)] for _ in range(row)]
        # 进行k次交易
        for i in range(k):
            maxdiff = trans[i % 2][0] - prices[0]
            for j in range(1, col):
                maxdiff = max(maxdiff, trans[i % 2][j - 1] - prices[j - 1])
                trans[(i + 1) % 2][j] = max(trans[(i + 1) % 2][j - 1],maxdiff + prices[j])
        return max(trans[0][col - 1], trans[1][col - 1])


源代码文件在这里.


目录
相关文章
|
8月前
leetcode-1345:跳跃游戏 IV
leetcode-1345:跳跃游戏 IV
51 0
|
5月前
|
算法
leetcode188 买卖股票的最佳时机IV
leetcode188 买卖股票的最佳时机IV
70 0
|
8月前
|
算法
leetcode代码记录(买卖股票的最佳时机 IV
leetcode代码记录(买卖股票的最佳时机 IV
47 2
|
7月前
|
存储 算法 数据可视化
LeetCode 力扣题目:买卖股票的最佳时机 IV
LeetCode 力扣题目:买卖股票的最佳时机 IV
|
7月前
dp表,哈希表,力扣5.最长回文子串力扣1745.分割回文串IV力扣132.分割回文串II优先级队列(堆)是什么下面是手动实现小根堆力扣1046.最后一块石头的重量
dp表,哈希表,力扣5.最长回文子串力扣1745.分割回文串IV力扣132.分割回文串II优先级队列(堆)是什么下面是手动实现小根堆力扣1046.最后一块石头的重量
|
8月前
|
SQL
leetcode-SQL-550. 游戏玩法分析 IV
leetcode-SQL-550. 游戏玩法分析 IV
57 1
|
8月前
代码随想录Day42 动态规划10 LeetCode T123 买卖股票的最佳时机III T188买卖股票的最佳时机IV
代码随想录Day42 动态规划10 LeetCode T123 买卖股票的最佳时机III T188买卖股票的最佳时机IV
50 0
|
8月前
|
测试技术
代码随想录 Day37 完全背包理论基础 卡码网T52 LeetCode T518 零钱兑换II T377 组合总和IV
代码随想录 Day37 完全背包理论基础 卡码网T52 LeetCode T518 零钱兑换II T377 组合总和IV
67 0
|
8月前
|
缓存 算法 测试技术
【单调栈】【二分查找】LeetCode: 2454.下一个更大元素 IV
【单调栈】【二分查找】LeetCode: 2454.下一个更大元素 IV
|
8月前
leetcode-6111:螺旋矩阵 IV
leetcode-6111:螺旋矩阵 IV
49 0