2019-01-19

LeetCode 188. Best Time to Buy and Sell Stock IV.jpg

LeetCode 188. Best Time to Buy and Sell Stock IV

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])

源代码文件在这里.
©本文首发于何睿的博客,欢迎转载,转载需保留文章来源,作者信息和本声明.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容

  • 一、2017年年报 1、利润表 (1)实现收入 103.95 亿元,同比增长 20.50%,实现净利润 25.58...
    我是牛我爱豆豆阅读 432评论 0 0
  • 热线:13013821612谭先生 欢迎新老客户一如既往惠顾! 地址:常熟市沙家浜大闸蟹交易市场84号门市部,苏嘉...
    谭良根阅读 1,918评论 6 5
  • 我家没有男孩,我和姐姐都是女孩儿,家里的重大的责任落到了我的头上。爸爸妈妈都期待我成为家里的顶梁柱,可以是赚大钱的...
    蜗牛等待爱情阅读 455评论 0 1
  • 独臂勿入 某团体举办活动,参加的人很多。引人注目的是残疾人也有参加的。但是门卫宣布了举办方的一个规定:无腿的可以参...
    泠泠涧水流阅读 192评论 0 2