Best Time to Buy and Sell Stock IV

Description

Given an array prices and the i-th element of it represents the price of a stock on the i-th day.

You may complete at most k transactions. What's the maximum profit?

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

Example

样例 1:

输入: k = 2, prices = [4, 4, 6, 1, 1, 4, 2 ,5]
输出: 6
解释: 以 4 买入, 以 6 卖出. 然后再以 1 买入, 以 5 卖出. 利润为 2 + 4 = 6.

样例 2:

输入: k = 1, prices = [3, 2, 1]
输出: 0
解释: 不进行交易

Challenge

O(nk) 时间复杂度. n 是 prices 数组的大小.

 

思路:

假设一共有 n 天, 那么这 n 天最多能够完成 n / 2 比交易, 也就是说, 当 k * 2 >= n 时, 就变成了 买卖股票的最佳时机 II, 反之, 我们可以作为动态规划问题解决:

定义:

  • globalbest[i][j] 表示前i天,至多进行j次交易时的最大获益
  • mustsell[i][j] 表示前i天,至多进行j次交易,并且第i天卖出手中的股票时的最大获益

状态转移:

  • mustsell[i][j] = max(globalbest[i - 1][j - 1], mustsell[i - 1][j]) + prices[i] - prices[i - 1]
  • globalbest[i][j] = max(globalbest[i - 1][j], mustsell[i][j])

边界: mustsell[0][i] = globalbest[0][i] = 0

优化: 滚动数组优化两个状态的空间至一维数组.

public class Solution {
    /**
     * @param K: An integer
     * @param prices: An integer array
     * @return: Maximum profit
     */
   public int maxProfit(int K, int[] P) {
        int n = P.length;
        if (n == 0) {
            return 0;
        }

        int i, j, k;
        if (K > n / 2) {
            // best time to buy and sell stock ii
            int tmp = 0;
            for (i = 0; i < n - 1; ++i) {
                tmp += Math.max(0, P[i + 1] - P[i]);
            }

            return tmp;
        }

        int[][] f = new int[n + 1][2 * K + 1 + 1];
        for (k = 1; k <= 2 * K + 1; ++k) {
            f[0][k] = Integer.MIN_VALUE; // impossible
        }

        f[0][1] = 0;
        for (i = 1; i <= n; ++i) {
            // 阶段1, 3, .. 2 * K + 1: f[i][j] = max{f[i-1][j], f[i-1][j-1] + Pi-1 – Pi-2}
            for (j = 1; j <= 2 * K + 1; j += 2) {
                f[i][j] = f[i - 1][j];
                if (j > 1 && i > 1 && f[i - 1][j - 1] != Integer.MIN_VALUE) {
                    f[i][j] = Math.max(f[i][j], f[i - 1][j - 1] + P[i - 1] - P[i - 2]);
                }
            }

            // 阶段2, 4.., 2K: f[i][j] = max{f[i-1][j] + Pi-1 – Pi-2, f[i-1][j-1]}
            for (j = 2; j <= 2 * K + 1; j += 2) {
                f[i][j] = f[i - 1][j - 1];
                if (i > 1 && f[i - 1][j] != Integer.MIN_VALUE) {
                    f[i][j] = Math.max(f[i][j], f[i - 1][j] + P[i - 1] - P[i - 2]);
                }
            }
        }

        int res = 0;
        for (j = 1; j <= 2 * K + 1; j += 2) {
            res = Math.max(res, f[n][j]);
        }

        return res;
    }
}

  

posted @ 2019-12-21 21:30  YuriFLAG  阅读(263)  评论(0)    收藏  举报