【leetcode】股票買賣系列總結


股票買賣系列總結

股票買賣系列的題目在面試中還是比較經典的,這里對這一系列做一些簡單的總結。

1. 只允許買賣一次

假設股票價格序列為(3, 5, 7, 3, 8, 1)

動態規划。整個過程中的行為選擇有3種,買/賣/無操作。

\(dp[i]\)表示第\(i\)天的行為是”賣出“時,能得到的最大收益。顯然,我們固定了賣出的時間,只要在這個時間點之前的時間中選擇股票價格比最小的時候買入,就可以確定\(dp[i]\)的值。

所以我們可以遍歷價格序列,cur_min不斷更新以記錄當前時間點之前的股票最低價格,所以\(dp[i] = max(0, prices[i]-cur\_min)\),最后所有dp[i]中的最大值就是只進行一次買賣能得到的最大利潤。可以在求\(dp[i]\)的同時用一個變量來記錄其最大值。

因為\(dp[i]\)只用到一次,所以沒必要開一個數組專門來存儲。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        // 只允許最多一次交易 求最大收益
        // 記錄當前最小  cur_min dp[i]表示在第i天賣出的最大收益
        if(prices.size()<=1) return 0;
        int cur_min = prices[0], res = 0;
        for(int i=1; i<prices.size(); i++){
            res = max(prices[i]-cur_min, res);// dp[i] = prices[i] - cur_min;
            cur_min = min(cur_min, prices[i]);
        }
        return res;
    }
};

2. 不限制買賣次數

假設股票價格序列為(1, 2, 3, 4, 5)。其實這是一個特殊情況,我們可以在第0天買入,然后在最后一天賣出。此時最大收益就是4。

我們也可以在第0天買入,第一天賣出。第一天買入,第二天賣出。。。這樣的結果和上面是一樣的,最大收益都是4。

所以,對於比較常規的情況,比如說(7, 6, 3, 4, 5),在第一天和第二天是不能買入的,因為,之后找不到比當前價格更大的數了。另外的話,可以在3的時候買入,4的時候賣出,然后4又買入,5賣出。最后最大收益是2.

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        // 不限制股票的買賣次數
        // 只要是遇到比當前價格更高的就賣掉
        if(prices.size() <=1) return 0;
        int buy = INT_MAX, profit = 0;
        for(int i=0; i<prices.size(); i++){
            if(prices[i]<=buy) buy = prices[i];
            else{
                profit += prices[i]-buy;
                buy = prices[i];
            }
        }
        return profit;
    }
};

可以將上面代碼進行簡化:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.size() <=1) return 0;
        int buy = INT_MAX, profit = 0;
        for(int i=0; i<prices.size(); i++){
            if(prices[i] > buy) profit += prices[i] - buy;// 只有當當前價格大於假設買入的價格時,才進行賣出
            buy = prices[i];// 每次都在當前進行“假設”買入
        }
        return profit;
    }
};

3. 最多只能買賣2次

\(buy1\)表示在第\(i\)天進行第一次買入時可以獲得的最大收益
\(buy2\)表示在第\(i\)天進行第二次買入時可以獲得的最大收益
\(sell1\)表示在第\(i\)天進行第一次賣出時可以獲得的最大收益
\(sell2\)表示在第\(i\)天進行第二次賣出時可以獲得的最大收益

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        // 最多只能買賣2次 求最大收益
        // buy1 sell1 buy2 sell2 分別表示當前天如果是第一次買/賣、第二次買/賣時的最大收益
        int buy1 = INT_MIN, buy2 = INT_MIN, sell1 = 0, sell2 = 0;
        for(int price:prices){
            sell2 = max(sell2, buy2+price);
            buy2 = max(buy2, sell1-price);
            sell1 = max(sell1, buy1+price);
            buy1 = max(buy1, -price);
        }
        return sell2;
    }
};

4. 有冷凍期不限制買賣次數

\(buy[i]\)表示第\(i\)天之前最后一次行為是buy時,最大的收益

\(sell[i]\)表示第\(i\)天之前最后一次行為是sell時,最大的收益

\(rest[i]\)表示第\(i\)天之前最后一次行為是冷凍rest時,最大的收益

\(buy[i] = max(buy[i-1], rest[i-1] - prices[i])\),max(第i天冷凍, 第i天是賣出)

\(sell[i] = max(sell[i-1], buy[i-1] + prices[i])\),max(第i天冷凍,第i天是買入)

\(rest[i] = max(rest[i-1], buy[i-1], sell[i-1])\)

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        // 有冷凍期 不限制買賣次數 但是賣完股票后有一天的冷凍期才能再接着買
        int n = prices.size();
        if(n<=1) return 0;
        vector<int> buy(n, INT_MIN), sell(n, INT_MIN), rest(n, INT_MIN);
        buy[0] = -prices[0];
        sell[0] = 0;
        rest[0] = 0;
        for(int i=1; i<n; i++){
            buy[i] = max(buy[i-1], rest[i-1]-prices[i]);
            sell[i] = max(sell[i-1], buy[i-1]+prices[i]);
            rest[i] = max(rest[i-1], max(buy[i-1], sell[i-1]));
        }
        return max(buy[n-1], max(sell[n-1], rest[n-1]));
    }
};


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM