zoukankan      html  css  js  c++  java
  • 【LeetCode】188、买卖股票的最佳时机 IV

    Best Time to Buy and Sell Stock IV

    题目等级:Hard

    题目描述:

    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次交易,必须在再次购买前出售掉之前的股票。


    解题思路(动态规划):

      股票怎么都买卖不完了。。。。

      本题是股票买卖系列的第四题,前面三道分别处理了一次交易、无数次交易、两次交易的情形,其主要思想就是动态规划,这里直接扩展到了任意次(k次),难度可以说是相当大了,自己没有什么思路,参考了网上的解答,这里做一个解释和记录吧。

      和前面三道一样,动态规划仍然是解决此题的思路,只不过这里的状态定义很复杂。

      这里定义两个变量,local和global分别表示全局最优和局部最优,定义如下:local[i][j]表示在到达第i天时最多可进行j次交易并且最后一次交易在最后一天卖出的最大利润,此为局部最优。global[i][j]表示到达第i天时最多可进行j次交易的最大利润,此为全局最优。

      我们首先来看global,它代表全局最优,那么global[i][j] = max(local[i][j], global[i - 1][j]),这个相对好理解一些,是动态规划的常规用法,全局最优等于前一天的全局最优和当前的局部最优的较大者。

      而local的更新比较复杂,主要是注意local[i][j]表示的是最后一支股票在第i天卖出,也就是第 i 天卖第 j 支股票,这样的话有三种情况:

    • 之前已经将j次交易进行完了,最后一次是今天买,今天卖,相当于啥也没干,则 Local(i, j) = Global(i-1, j-1).
    • 第j次交易是昨天买的,第i天卖,则Local(i, j) = Global(i-1, j-1) + diff
    • 第j次交易是更早之前买的,第i天卖,则Local(i, j) = Local(i-1, j) + diff,也就是Local(i-1, j)代表最后一次交易第i-1天卖出,加diff就是说昨天不卖,留到今天卖。

      其中diff=prices[i]-prices[i-1]

      由此分析,可以得出local的递推公式:local[i][j] = max(global[i - 1][j - 1], local[i - 1][j]) + diff

      所以,总结起来,本题的解题思路是以下三个公式:

    diff = prices[i] - prices[i - 1]
    global[i][j] = max(local[i][j], global[i - 1][j])
    local[i][j] = max(global[i - 1][j - 1], local[i - 1][j]) + diff
    

      根据这个分析,给出以下代码实现:

    class Solution {
        public int maxProfit(int k, int[] prices) {
            if(prices==null || prices.length==0)
                return 0;
            int len=prices.length;
            if(len<2||k<1)
                return 0;
            if(k>=len) //交易次数多于天数,可以按照无数次来直接解决
                return getMax(prices);
            int[] global=new int[k+1];
            int[] local=new int[k+1];
            for(int i=0;i<len-1;i++){
                int diff=prices[i+1]-prices[i];
                for(int j=k;j>=1;--j){   //为了取到上一次的global[j-1],需要从后往前遍历,否则会覆盖
                    local[j]=Math.max(global[j-1],local[j])+diff;
                    global[j]=Math.max(global[j],local[j]);
                }
            }
            return global[k];
        }
        public int getMax(int[] prices){
            int res = 0;
            for (int i = 1; i < prices.length; ++i) {
                if (prices[i] > prices[i - 1])
                    res += (prices[i] - prices[i - 1]);
            }
            return res;
        }
    }
    

      时间复杂度:O(n*k),空间复杂度:O(2k)

    总结

      太难了。。。本题确实有相当的难度,如何确定状态和确定递推关系很复杂,另外代码实现中一位数组代替二维也是一个很好的解决办法。这也是买卖股票这些题目中最难的一道了,接下来还有两道相关的变形。

  • 相关阅读:
    android-手势密码
    MS SQL 技巧总结--持续更新
    MySQL 笔记一
    spring 家族
    Java集合
    javaScript
    java 知识点随记
    MySQL 知识点随记
    odoo 权限杂记
    win10 Ubuntu子系统安装&odoo10社区版安装
  • 原文地址:https://www.cnblogs.com/gzshan/p/11116756.html
Copyright © 2011-2022 走看看