LeetCode OJ--Best Time to Buy and Sell Stock III
http://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/
这三道题,很好的进阶。1题简单处理,2题使用贪心,3题使用动态规划。
话说这叫一维动态规划,嗯。又复习了《算法导论》中和贪心以及动态规划有关的知识,记录如下:
动态规划的标志:最优子结构、子问题重叠。
1.找最优子结构
2.定义递归公示(列一个式子出来,并定义好这个式子到底是什么意思)。
3.写自底向上或递归备忘录法。
比如本问题:f(i,j) = max{f(i,k)+f(k,j)} 其中:f(i,j)表示从i到j的所有数,进行一次交易能获得的最多的钱数。最终要求的是f(0,n-1),k从1到n-2.
再深化一下:
fp(i,j)表示从i 到 j 进行最多进行 p 次交易可以获得的钱数,则:
fp(i,j) = max {fp-1(i,j), fp-p'(i,k)+fp'(k,j)} 其中:p'从1到p-1,k从i+1到j-1.
这大概叫二维动态规划(或许)。
贪心算法是从局部最优,能够做到全局最优。可分成一步步的,当前的选择受之前做过的选择的影响。而动态规划,是受后面要做的选择的影响。
于是有了下面代码,复杂度O(n2)然后超时了。
class Solution { public: //start 第一个元素,end 最后一个元素的下标 int onceBuyAndSell(vector<int> &prices,int start,int end) { int ans = 0; int max = prices[end]; for(int i = end - 1;i>=start;i--) { if(max - prices[i]>ans) ans = max - prices[i]; if(prices[i]>max) max = prices[i]; } return ans; } int maxProfit(vector<int> &prices) { if(prices.empty()) return NULL; if(prices.size()==1) return 0; int ans = onceBuyAndSell(prices,0,prices.size()-1); if(prices.size()<4 || ans == 0) return ans; int temp = 0; for(int itor = 2;itor<prices.size()-2;itor++) { temp = onceBuyAndSell(prices,0,itor) + onceBuyAndSell(prices,itor+1,prices.size()-1); if(temp> ans) ans = temp; } return ans; } };
使用了动态规划中打表的方法,降低了复杂度O(n).代码如下:
class Solution { public: vector<int> ansN;
//ansN[i]表示,从i到最后的所有元素,只进行一次交易的话,可以得到的最多值。 void onceBuyAndSell(vector<int> &prices,int start,int end) { int ans = 0; int max = prices[end]; ansN[end] = 0; for(int i = end - 1;i>=start;i--) { if(max - prices[i]>ans) ans = max - prices[i]; if(prices[i]>max) max = prices[i]; ansN[i] = ans; } } int maxProfit(vector<int> &prices) { if(prices.empty()) return NULL; if(prices.size()==1) return 0; ansN.resize(prices.size()); //先来一遍从后面计算的。 onceBuyAndSell(prices,0,prices.size()-1); if(prices.size()<4 ) return ansN[0]; int min = prices[0]; int ans2 = 0; int ans = ansN[0]; for(int itor = 1;itor<prices.size()-2;itor++) { if(prices[itor] - min>ans2) ans2 = prices[itor] - min; if(prices[itor]<min) min = prices[itor]; if(ans2 + ansN[itor+1]> ans) ans = ans2 + ansN[itor+1]; } return ans; } };