Leetcode 188 Best Time to Buy and Sell Stock IV 至多k次買賣股票最大收益

原題地址

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

題目描述

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.
設計一個算法來計算最大收益。你至多可以完成k次交易。

Note:
注意:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
你不能同時進行多次交易(即,在你買入股票之前必須賣掉手裏的股票)。

解題思路

這是這個系列的第四題,前三題如下:

參考了網上諸多大神的代碼,有位大神說這個題是II和III的結合版。在某特殊情況下是II,其他情況下是III的升級。後面再詳述。

網上的代碼大致分兩種,時間複雜度O(n*k)空間複雜度O(n),但是兩種的角度不同。

第一種,大家可以看下面的博文:

另外一種,大家可以參考以下文章:

第一種維護兩個數組,local[][]和global[][],其中global[i][j]表示到第i天時完成j次交易的最大收益local[i][j]表示到第i天時完成j次交易並且最後一次交易發生在第i天時的最大收益

global的推導公式如下:

global[i][j] = max(local[i][j], global[i-1][j]);
即,到第i天完成j次交易的最大收益,要麼是第j次交易發生在第i天時的最大收益,要麼是到第i-1天完成j次交易時的最大收益。

local的推導公式如下:

local[i][j] = max(global[i-1][j-1]+max(diff,0), local[i-1][j]+diff);
需要看兩個量,第一個是全局global到i-1天進行j-1次交易,然後加上今天的交易,如果今天是賺錢的話(也就是前面只要j-1次交易,最後一次交易取當前天);第二個量則是取local第i-1天j次交易,然後加上今天的差值(這裏因爲local[i-1][j]比如包含第i-1天賣出的交易,所以現在變成第i天賣出,並不會增加交易次數,而且這裏無論diff是不是大於0都一定要加上,因爲否則就不滿足local[i][j]必須在最後一天賣出的條件了)。

代碼請看代碼一。

第二種想法是維護兩個數組buy和sell,buy[i]表示完成第i筆交易的買入動作時的最大收益sell[i]表示完成第i筆交易的賣出動作時的最大收益。初始情況下buy[i]=MIN,sell[i]=0。

buy[i]的推導

buy[i] = max(buy[i], sell[i-1]-prices[j])

即,第i-1次完成賣出時的最大收益再減去第j天的價格,有可能更新第i次完成買入時的最大收益。

sell[i]的推導

sell[i] = max(sell[i], buy[i]+prices[j])

即,第i次完成買入時的最大收益再加上第j天的價格,有可能更新第i次賣出時的最大收益。

代碼請見代碼二。

代碼

代碼一

class Solution {
public:
    /**
     * 計算最大收益
     * @param k : 至多進行k次買賣
     * @param prices : 每日價格
     * @return : 最大收益 
     */
    int maxProfit(int k, vector<int>& prices) {
        int pricesSize = prices.size();

        /* 如果價格數據爲空或只有一個數據,或者不能進行買賣,返回0  */
        if (pricesSize <= 1 || k <= 0) return 0;

        /* k>=pricesSize,相當於不限交易次數 */
        if (k >= pricesSize) {
            int max = 0;
            for (int i = 1; i < pricesSize; ++i)
                if (prices[i] > prices[i-1])
                    max += prices[i] - prices[i-1];
            return max;
        }

        int *local = new int[k + 1];
        int *global = new int[k + 1];
        for (int i = 0; i <= k; ++i)
            local[i] = global[i] = 0;

        for (int i = 1; i < pricesSize; ++i) {
            int diff = prices[i] - prices[i - 1];
            for (int j = k; j > 0; --j) {
                local[j] = bigger(global[j - 1] + bigger(diff, 0), local[j] + diff);
                global[j] = bigger(local[j], global[j]);
            }
        }

        int max = global[k];
        delete(local);
        delete(global);
        return max;
    }

private:
    int bigger(int a, int b) {
        return a > b ? a : b;
    }
};

完整代碼 https://github.com/Orange1991/leetcode/blob/master/188/cpp/solution2.cpp

代碼二

class Solution {
public:
    /**
     * 計算最大收益
     * @param k : 至多進行k次買賣
     * @param prices : 每日價格
     * @return : 最大收益 
     */
    int maxProfit(int k, vector<int>& prices) {
        int pricesSize = prices.size();

        /* 如果價格數據爲空或只有一個數據,或者不能進行買賣,返回0  */
        if (pricesSize <= 1 || k <= 0) return 0;

        /* k>=pricesSize,相當於不限交易次數 */
        if (k >= pricesSize) {
            int max = 0;
            for (int i = 1; i < pricesSize; ++i)
                if (prices[i] > prices[i-1])
                    max += prices[i] - prices[i-1];
            return max;
        }

        // 第i次買入和賣出時的最大收益
        vector<int> buy(pricesSize + 1, numeric_limits<int>::min()), sell(pricesSize + 1); 

        for (int day = 0; day < pricesSize; ++day) {
            for (int transaction = 1; transaction <= k; ++transaction) {
                buy[transaction] = bigger(buy[transaction], sell[transaction - 1] - prices[day]);
                sell[transaction] = bigger(sell[transaction], buy[transaction] + prices[day]);
            }
        }

        return sell[k];
    }

private:
    int bigger(int a, int b) {
        return a > b ? a : b;
    }
};

完整代碼 https://github.com/Orange1991/leetcode/blob/master/188/cpp/main.cpp


2015/8/12

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章