LeetCode--Best Time to Buy and Sell Stock IV(DP + 滚动数组)

来源:互联网 发布:强情节 知乎 编辑:程序博客网 时间:2024/06/05 16:02

题目:https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/

题意:已知第1天、第2天......第N天的股票价格,每天只能进行一次买或者卖,且规定手里的股票卖出之前不能买进新的股票,问在最多进行K次交易的情况下,采用最优方案净利润能有多少。

分析:

1、设j天完成不超过i次交易能得到的最大收益是f(i,j),显然f(0,0) = 0,f(i, 1) = 0(因为只有1天不能完成任何交易)

2、对最后一天也就是第j天发生的情况进行分类,第j天可能没有买卖,也可能最后一次卖出手里的股票,即

      f(i, j) = max{ f(i-1, j), f(i, j-1), f(i-1,k-1) + a[j] - a[k] },其中k >= 1 && k < j,即最后一天卖出的股票可能是第1天、第2天......第j-1天买入的股票

3、状态方程有了,似乎可以直接写了,但由于k的存在,这一算法的复杂度是O(k*n*n)的,在大数据情况下会TLE,我们看看能不能对后面这个f(i-1,k-1) + a[j] - a[k]做一些分析

4、我们令g(i, j) = f(i-1, k-1) - a[k],其中k >= 1 && k < j,那它表示什么意思呢,即最后第j天之前,最多进行了i-1次交易,且最后一次买入发生在第k天,这一过程之后手里money最多还有多少(或最少还欠多少),显然g(i, 1) = 0(因为第1天之前最多进行0次交易),g(i, 2) = f(i-1, 0) - a[1],将k带入,我们可以看到:

g(i, j) = max{ f(i-1, 0) - a[1], f(i-1, 1) - a[2], ..., f(i-1, j-2) - a[j-1] }

g(i, j+1) = max{ f(i-1, 0) - a[1], f(i-1, 1) - a[2], ..., f(i-1, j-2) - a[j-1], f(i-1, j-1) - a[j] }

               = max{ g(i, j), f(i-1, j-1) - a[j] }

即g(i, j)的递推会用到f(i, j)的状态

5、将g(i, j)带入我们的状态方程,则 

g(i, j) = max{ g(i, j-1), f(i-1, j-2) - a[j-1] }

f(i, j) = max{  f(i-1, j), f(i, j-1), g(i, j) + a[j] }

可以看到g的当前状态仅和本层前一个状态、f的上一层前一个状态有关,f当前状态仅和上一层的当前状态、本层的前一个状态、g的当前状态有关,因此我们可以采用滚动数组的形式,仅保留2层状态,即能完成状态转移的过程

6、最后还有一个优化(有点像多重背包可以分成完全背包和0-1背包):

当2k >= n时,即我们可以做到在任意一天买入任意之后一天卖出,在直方图中容易看出这相当于只要有利可图我们就能获得


class Solution {public:    int allProfit(vector<int>& prices){        int tot = 0;        for(int i = 1; i < prices.size(); ++i){            tot += max(0, prices[i] - prices[i-1]);        }        return tot;    }    int maxProfit(int k, vector<int> &prices) {        int n = prices.size();        if(k * 2 >= n) return allProfit(prices);                vector<int> mem((n + 1) * 2, 0);        int *pref = &mem[0], *curf = &mem[n+1], g, *a = &prices[0] - 1;        for(int i = 1; i <= k; ++i){            //递推第1天和第2天的情况,因为比较特殊            curf[1] = 0;                  //g[1] = 0, g[2] = pref[0] - a[1]            curf[2] = max(0, a[2] - a[1]);  g = -a[1];            //递推之后的情况            for(int j = 3; j <= n; ++j){                g = max(g, pref[j-2] - a[j-1]);                curf[j] = max(max(pref[j], curf[j-1]), g + a[j]);            }            swap(pref, curf);        }        return pref[n];    }};

0 0
原创粉丝点击