1. 程式人生 > >LeetCode 買賣股票的合適時間

LeetCode 買賣股票的合適時間

最近在看貪心演算法及相關內容,找出了leetcode相關的專題來做,碰到了買賣股票的一系列問題,故記錄以備之。

一、入門一級:只能買賣一次股票,求最大利潤

Title: Best Time to Buy and Sell Stock

Say you have an array for which the ith element is the price of a given stock on day i.

If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Example 1:
Input: [7, 1, 5, 3, 6, 4]
Output: 5

max. difference = 6-1 = 5 (not 7-1 = 6, as selling price needs to be larger than buying price)
Example 2:
Input: [7, 6, 4, 3, 1]
Output: 0

In this case, no transaction is done, i.e. max profit = 0.

思路:本題的解法是記錄下最小值並與之後遇到的值與該最小值做差並保留最大值。

class Solution {
public
: int maxProfit(vector<int>& prices) { int n = prices.size(), buy = INT_MIN, sell = 0; if(n==0) return 0; for(int i=0; i<n; i++) { buy = max(buy, -prices[i]); sell = max(sell, prices[i] + buy); } return sell; } };

二、入門二級:可以多次買入賣出,求最大利潤

Title: Best Time to Buy and Sell Stock II

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 as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

思路:本題可簡化為只要後一天的股價高於前一天的,即可進行一次買入賣出操作。

class Solution {
public:
    int maxProfit(vector<int>& prices) {

        int buy = INT_MIN, sell = 0, n = prices.size();
        if(n==0) return 0;

        for(int i=0; i<n; i++)
        {
            buy = max(buy, sell-prices[i]);
            sell = max(sell, buy + prices[i]);
        }
       return sell;
    }
};

三、進階級:最多可進行兩次買賣操作

Title: Best Time to Buy and Sell Stock III
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 two transactions.

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

思路:本題相當於前兩題的合併,分別儲存兩次交易的買入賣出後的利潤,寫程式時應該清楚何種方法可僅進行一次買入賣出操作,何種方法為可進行多次買入賣出操作。

class Solution {
public:
    int maxProfit(vector<int>& prices) {

        int n = prices.size();
        if(n==0) return 0;
        int sell1 = 0, sell2 = 0, buy1 = INT_MIN, buy2 = INT_MIN;

        for(int i =0; i<n; i++)
        {
            buy1 = max(buy1, -prices[i]);
            sell1 = max(sell1, prices[i]+buy1);
            buy2 = max(buy2, sell1-prices[i]);
            sell2 = max(sell2, prices[i]+buy2);
        }        
        return sell2;        
       }
};

四、變態級:最多進行k次交易

Title: 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.

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

思路:
分成 k > n/2 及 k <= n/2 兩部分考慮:
1. k > n/2 時,可歸為上述樣例二中的情況(即可進行無限次交易);
2. k <= n/2 時, 將每次的買入、賣出利潤儲存在陣列中(與動態規劃相結合)。

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {

        int n = prices.size();

        if(k>n/2)
        {
            int buy = INT_MIN, sell = 0;
            for(int i=0; i<n; i++)
            {
                buy = max(buy, sell-prices[i]);
                sell = max(sell, buy+prices[i]);
            }
            return sell;
        }

        vector<int> sell(k+1, 0);
        vector<int> buy(k+1, 0);

        for(int i=0; i<=k; i++) buy[i] = INT_MIN;

        for(int i=0; i<n; i++)
        {
            for(int j=1; j<k+1; j++)
            {

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

            }
        }
        return sell[k];        
    }
};

五、改進級:可進行多次交易,但每次交易後需要“冷靜”一天

Title: Best Time to Buy and Sell Stock with Cooldown

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 as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions:

You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)
Example:

prices = [1, 2, 3, 0, 2]
maxProfit = 3
transactions = [buy, sell, cooldown, buy, sell]

思路: 將前一天的賣出值儲存,用於之後交易時條件判定。

class Solution {
public:
    int maxProfit(vector<int>& prices) {

        int n = prices.size(), buy = INT_MIN, sell = 0, sell_pre = 0;
        for(int i=0; i<n; i++)
        {
            int old_sell = sell;
            buy = max(buy, sell_pre - prices[i]);
            sell = max(old_sell, buy + prices[i]);
            sell_pre = old_sell;
        }
        return sell;
    }
};

六、另一版改進級:每次交易需支付手續費,買賣次數無限制

Title:Best Time to Buy and Sell Stock with Transaction Fee

our are given an array of integers prices, for which the i-th element is the price of a given stock on day i; and a non-negative integer fee representing a transaction fee.

You may complete as many transactions as you like, but you need to pay the transaction fee for each transaction. You may not buy more than 1 share of a stock at a time (ie. you must sell the stock share before you buy again.)

Return the maximum profit you can make.

Example 1:
Input: prices = [1, 3, 2, 8, 4, 9], fee = 2
Output: 8
Explanation: The maximum profit can be achieved by:
Buying at prices[0] = 1
Selling at prices[3] = 8
Buying at prices[4] = 4
Selling at prices[5] = 9
The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {

        int n = prices.size(), buy = INT_MIN, sell = 0;
        for(int i=0; i<n; i++)
        {
            buy = max(buy, sell-fee-prices[i]);
            sell = max(sell, buy+prices[i]);
        }
        return sell;
    }
};

綜上所述, 買賣股票最關鍵的是要將問題分為兩種狀態:當前手中持有股票時最大利潤為多少,及將手中股票賣出後最大利潤為多少。根據要求計算每一狀態下的最佳值(確定狀態的轉換方程很重要!),最後返回手中股票賣出後的最大利潤即為所求的最終結果。