【easy->hard】 Best time to buy and sell stock -- 121, 122, 123, 188

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 (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.優化

Note that you cannot sell a stock before you buy one.this

Example 1:atom

Input: [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
             Not 7-1 = 6, as selling price needs to be larger than buying price.

Example 2:spa

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        // 方法1
        int max = 0;
        for (int i=0; i<prices.size(); i++){
            for (int j=i+1; j<prices.size(); j++){
                if (prices[j]-prices[i] > max)
                    max = prices[j]-prices[i];
            }
        }
        return max;
        
        // 方法2
        if (prices.empty()) return 0;
        int i=prices.size()-1, ans=0, maxp=prices[i];
        for (--i; i>=0; --i){
            ans=max(ans, maxp-prices[i]);
            maxp=max(maxp, prices[i]); // 逆向,維護一個max
        }
        return ans;
    }
};

==================================================================================================================code

 

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

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times).blog

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

Example 1:element

Input: [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
             Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.

Example 2:

Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
             Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
             engaging multiple transactions at the same time. You must sell before buying again.

Example 3:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        // 貪心法: 只要相鄰的兩天股票的價格是上升的, 咱們就進行一次交易, 得到必定利潤.
        // 這樣的策略不必定是最小的交易次數, 可是必定會獲得最大的利潤.
        int max = 0;
        for (int i=1; i<prices.size(); i++){
            if (prices[i]-prices[i-1]>0)
                max += (prices[i]-prices[i-1]);
        }
        return max;
    }
};

====================================================================================================================

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 (i.e., you must sell the stock before you buy again).

Example 1:

Input: [3,3,5,0,0,3,1,4]
Output: 6
Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
             Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.

Example 2:

Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
             Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
             engaging multiple transactions at the same time. You must sell before buying again.

Example 3:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

https://zhuanlan.zhihu.com/p/53849130
class Solution:
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        nums = len(prices)
        if nums <= 1:
            return 0
        leftoright = [0 for _ in range(nums)] # [0, 0, 0, ...]
        
        minprice = prices[0]
        # 先從左往右遍歷,在只容許進行一次交易的前提下:求一遍最大利潤
        # 即以當前價格爲賣出價格
        for i in range(1, nums):
            # 更新買入價格的最小值
            minprice = min(minprice, prices[i])
            # 從第0天到第i天,獲取最大利潤
            # 若當天什麼都不作,則得到前一天的利潤;
            # 若當前進行一次交易,則利潤爲當天價格(賣出價格)減去前面最低點的價格
            # 因而當天的最大利潤爲上面兩種狀況的最大值
            leftoright[i] = max(leftoright[i-1], prices[i]-minprice)
            
        maxprice = prices[-1]
        rightoleft = [0 for _ in range(nums)]
        # 再從右往左遍歷,在只容許進行一次交易的前提下:求一遍最大利潤
        # 即以當天價格爲買入價格
        for i in range(nums-2, -1, -1):
            # 更新賣出價格的最大值
            maxprice = max(prices[i], maxprice)
            # 同上,若第i天什麼都不作,則獲利爲第i+天的利潤,
            # 若進行一次交易,則利潤爲當天價格減去最高賣出價格
            # 因而當天的最大利潤爲上面兩種狀況的最大值
            rightoleft[i] = max(rightoleft[i+1], maxprice-prices[i])
            
        # 將對應位置一一求和,即爲在最多容許兩次交易的狀況下的最大利潤
        res = [x+y for x, y in zip(leftoright, rightoleft)]
        
        return max(res)

 

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).

Example 1:

Input: [2,4,1], k = 2
Output: 2
Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.

Example 2:

Input: [3,2,6,5,0,3], k = 2
Output: 7
Explanation: Buy on day 2 (price = 2) and sell on day 3 (price = 6), profit = 6-2 = 4.
             Then buy on day 5 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.

解題思路

求最優解一般是動態規劃的一個明顯特徵。假設:

  • local[i][j]表示最後一次買賣在第i天賣出,同時交易次數小於等於j次的最大收益;
  • glocal[i][j]表示前i天完成小於等於j次交易的最大收益。

下面,咱們先來推導local[i][j]的狀態轉移方程。local[i][j]表示最後一次買賣在第i天賣出,同時交易次數小於等於j次的最大收益,那麼最後一次買賣的買入時刻存在兩種狀況:最後一次買賣在第i-1天買入和最後一次買賣的第i-1天前買入。

  1. 最後一次買賣在第i-1天買入:local[i][j]=global[i-1][j-1] + prices[i] - prices[i-1]。其中,prices[i] - prices[i-1]表示最後一次買賣股票的收入,global[i-1][j-1]表示以前i-1天完成小於等於j-1次交易的最大收益。
  2. 最後一次買賣在第i-1天前買入:local[i][j]=local[i-1][j]+prices[i]-prices[i-1]。其中,prices[i] - prices[i-1]表示最後一次買賣股票的收入,local[i-1][j]表示完成小於等於j次交易且最後一次交易在第i-1天完成的最大收益。這裏有的同窗可能存在疑問,爲何能夠這樣推導。緣由是,當你在第i-1天賣出完成第j次買賣時,若是你在這一天再次買入,並在下一天賣出,此時的交易等同於在第i-1天不賣出,等到第i天再賣出,所以交易次數依然爲j次,不會增長交易次數!

經過上面的兩步分析,咱們能夠知道,local[i][j]是這兩種狀況中的最優解,咱們獲得狀態轉移方程以下:

 

local[i][j]=max(global[i1][j1],local[i1][j])+(prices[i]prices[i1])local[i][j]=max(global[i−1][j−1],local[i−1][j])+(prices[i]−prices[i−1])

 

接下來,咱們分析上式中global[i][j]的狀態轉移方程。glocal[i][j]表示前i天完成小於等於j次交易的最大收益,它可能來自兩種狀況:

  1. 在前i-1天完成小於等於j次交易的最大收益,即global[i-1][j];
  2. 在第i天完成小於等於j次交易的最大收益,即local[i][j]。

所以,獲得global[i][j]的狀態轉移方程以下:

 

global[i][j]=max(global[i1][j],local[i][j])global[i][j]=max(global[i−1][j],local[i][j])

 

到這裏,這道題目已經得以解決,時間複雜度爲O(N*K)。當K很是大時,時間成本會上升,這裏能夠進一步優化:若是KN/2K≥N/2,那麼等同於你能夠進行無限次交易(K超過了可供交易的最大次數),那麼你只要貪心的進行買賣就能夠了(若是股票下跌,就在下跌前買入,下跌後賣出)。此時,時間複雜度爲O(N)

OK,到這裏,完美解決。真的完美了嗎?若是想進一步優化代碼空間複雜度的同窗能夠接着往下看。

在求解local[i][j]的過程當中,你會發現,他依賴於global[i-1][j-1]和local[i-1][j],咱們並不真的須要第一個維度,能夠把它簡化以下:

 

local[j]=max(global[j1],local[j])+(prices[i]prices[i1])local[j]=max(global[j−1],local[j])+(prices[i]−prices[i−1])

 

是否是很神奇?由於local[i][j]只依賴於local[i-1][j],而不依賴於local[i-2][j],所以咱們能夠在求解local[i][j]的同時,覆蓋以前的local[i-1][j]的值(它已經不須要了)。

同理,global[i][j]的求解能夠簡化以下:

 

global[j]=max(global[j],local[j])global[j]=max(global[j],local[j])

 

這裏有一點須要注意,由於local[i][j]的求解依賴於global[i-1][j-1],若是從左向右更新local和global的數組的話,global[j-1]此時已經被刷新爲global[i][j-1],而local[j]求解須要的是global[i-1][j-1],global竟然被提早更新了!所以,不能從左向右更新local和global數組,而是須要從右向左更新,這樣能夠保證每次計算local[j]時,使用的是global[i-1][j],而不是global[i][j]!

代碼實現

class Solution {
public:
    int maxProfit(int k, vector<int> &prices) {
        int max_profit = 0;
        if (k >= prices.size() / 2) {
            for (int i = 1; i < prices.size(); ++i) {
                if (prices[i] - prices[i - 1] > 0) {
                    max_profit += prices[i] - prices[i - 1];
                }
            }
        } else {
            vector<int> local(k+1);
            vector<int> global(k+1);
            for (int i = 1; i < prices.size(); ++i) {
                for (int j = k; j >= 1; --j) {
                    local[j] = max(global[j - 1], local[j]) + prices[i] - prices[i - 1];
                    global[j] = max(global[j], local[j]);
                }
            }
            max_profit = global[k];
        }
        return max_profit;
    }
   
};
相關文章
相關標籤/搜索