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