Say you have an array for which the ith element is the price of a given stock on day i.html
Design an algorithm to find the maximum profit. You may complete at most two transactions.spa
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again)..net
當遇到限制次數以及求最大的要求時,很天然要聯想到動規。設計
動規中不一樣的狀態設計,會有不一樣的時間複雜度。code
本題有兩種解法:htm
(1) blog
我最開始想到的是下面這種解法,可是Memory Limit Exceeced.ip
O(n^2)的解法element
很天然的咱們會想到記錄從開頭到第i個字符中進行k次交易可以獲得的最大收益,記爲dp[i][k].leetcode
進行更新:dp[i][k] = max{dp[j][k-1]+maxprofit(j...i)}, 0 <= j < i
這裏咱們須要用到每一個可能的區間中進行一次交易的最大收益,也就是I中的問題。
預先計算出全部的maxprofit的複雜度是O(n^2),dp的複雜度也是O(n^2).
Code:
class Solution { public: int maxProfit(vector<int> &prices) { int n = prices.size(); if(n == 0) return 0; vector<vector<int>> dp(n, vector<int>(3,0)); vector<vector<int>> maxprofit(n, vector<int>(n, 0)); for(int i = 0; i < n; i++) { int curmin = prices[i]; int curprofit = 0; for(int j = i+1; j < n; j++) { if(prices[j] < curmin) curmin = prices[j]; else{ int gap = prices[j] - curmin; if(gap > curprofit) curprofit = gap; } maxprofit[i][j] = curprofit; if(i == 0) dp[j][1] = curprofit; } } for(int i = 1; i < n; i++) { int tmp = dp[0][1] + maxprofit[0][i]; for(int j = 1; j < i; j++) { if(dp[j][1] + maxprofit[j][i] > tmp) tmp = dp[j][1]+maxprofit[j][i]; } dp[i][2] = tmp; } return dp[n-1][2]; } };
(2)O(n)的解法
參考了這個:http://blog.csdn.net/linhuanmars/article/details/23236995
從上面的分析中咱們很容易找出一個case, 例若有一個區間差別特別大,在很長時間內都是最優的選擇,而咱們的dp卻須要不斷的枚舉一些不可能構成最終解的區間。
怎麼樣更聰明的定義狀態呢?
上一種定義中,咱們是定義(i,j)中的最大的解,這樣不一樣的(i,j)對對應的多是同一種解;這樣咱們能夠用一個global變量來存儲;可是因爲處理的區間是不斷延伸的,後面出現的數字可能和當前末尾的組合起來行程更大的區間,所以咱們用一個local變量存儲當前以i結尾的最大的解的值。
擴展到可以選擇k個區間,咱們定義:
global(i,k) 表示截止到第i天,進行k次交易可以得到的最優解(不必定以最後一天結束)
local(i,k) 表示以第i天結束的k次交易可以得到的最優解
可以獲得遞推式:
local[i][k] = max{global[i-1][k-1], local[i-1][k]} + prices[i] - prices[i-1];
global[i][k] = max{global[i-1][k], local[i][k]};
初始值全爲零,最終解爲global[n-1][2]。
Code:
class Solution { public: int maxProfit(vector<int> &prices) { int n = prices.size(); if(n == 0) return 0; vector<vector<int>> global(n, vector<int>(3,0)); vector<vector<int>> local(n, vector<int>(3,0)); for(int j = 1; j <= 2; j++) { for(int i = 1; i < n; i++) { local[i][j] = max(global[i-1][j-1], local[i-1][j]) + prices[i] - prices[i-1]; global[i][j] = max(global[i-1][j], local[i][j]); } } return global[n-1][2]; } };
從其餘博客中找到了一種O(n)的解法,思路更簡單,可是不具有從2次交易推廣到k次的潛力。
主要的思路就是從前日後掃描一遍,找到從0到i的一次交易的最大收益,而後從後往前掃描一遍,獲得從i+1到n-1的最大收益。而後二者相加取最大便可。
傳送門:http://fisherlei.blogspot.com/2013/01/leetcode-best-time-to-buy-and-sell_3958.html