题目:
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,要求最大交易次数为k,求最大的利益。
思路:根据Best Time to Buy and Sell Stock III的思路,建立动态规划数组,
local[i][j]: 表示到达第i天的时候,在第i天完成最后一次交易,总共交易了j次的最大利益。
global[i][j]:表示到达第i天的时候,总共交易了j次的最大利益。
根据定义可知下面的递推公式:
对于lcoal数组,local[i][j]在local[i-1][j]的时候已经完成了j次交易,因此从i-1天到达第i天,无论差值是多少,都要加上,同时相比较的应该是global[i-1][j-1],i-1天完成了j-1次交易,第i天如果差值大于0即赚钱,则加上,不赚钱则加0,即递推公式为: local[i][j] = Math.max(local[i-1][j] + diff, global[i-1][j-1] + (diff > 0 ? diff : 0));
对于global数组就比较简单:global[i][j] = Math.max(local[i][j], global[i-1][j]);
下面是我第一次写的代码:
public class Solution { public int maxProfit(int k, int[] prices) { if(prices == null || prices.length < 2) return 0; int[][] local = new int[prices.length][k+1]; int[][] global = new int[prices.length][k+1]; for(int i = 1 ; i < prices.length ; i++){ int diff = prices[i] - prices[i-1]; for(int j = 1 ; j <= k ; j++){ local[i][j] = Math.max(local[i-1][j] + diff, global[i-1][j-1] + (diff > 0 ? diff : 0)); global[i][j] = Math.max(local[i][j], global[i-1][j]); } } return global[prices.length-1][k]; } }
这个时候,在k值很大的时候,如果prices数组不是很大,效果会非常的差,因此开始增加对k的判断,如果大于prices数组的长度,则题可以理解为在这些天内,不限次数的交易,最大的利益,那么只需改变为下面的代码:
public class Solution { public int maxProfit(int k, int[] prices) { if(prices == null || prices.length < 2) return 0; // 增加的判断 if(k >= prices.length) return solveMaxProfit(prices); int[][] local = new int[prices.length][k+1]; int[][] global = new int[prices.length][k+1]; for(int i = 1 ; i < prices.length ; i++){ int diff = prices[i] - prices[i-1]; for(int j = 1 ; j <= k ; j++){ local[i][j] = Math.max(local[i-1][j] + diff, global[i-1][j-1] + (diff > 0 ? diff : 0)); global[i][j] = Math.max(local[i][j], global[i-1][j]); } } return global[prices.length-1][k]; } // 增加的判断 public int solveMaxProfit(int[] prices) { int res = 0; for (int i = 1; i < prices.length; ++i) { if (prices[i] - prices[i - 1] > 0) { res += prices[i] - prices[i - 1]; } } return res; } }
最后参考了下别人的优化代码,自己的代码在动态规划的时候比较死板,浪费了大量无用的空间,自己观察两个数组在比较的时候,都只需要比较自己上面的一个数值,因此可以讲二维数组简化为一维,同时,在进行计算的时候,为了不覆盖上一次的内容,如果j从1 ~ k-1 下一次的循环就会利用到上一次循环的结果 而不是二位数组中的上层内容,因此j应倒叙取值,简化后的AC代码如下:
public class Solution { public int maxProfit(int k, int[] prices) { if(prices == null || prices.length < 2) return 0; if (k >= prices.length) return solveMaxProfit(prices); int[] local = new int[k+1]; //在第i天卖出一次 j次的 最大收益 int[] global = new int[k+1]; // j次的最大收益 local[0] = 0; global[0] = 0; for(int i = 1 ; i < prices.length ; i++){ int diff = prices[i] - prices[i-1]; for(int j = k; j >= 1; --j){ // 倒序 local[j] = Math.max(global[j-1] + (diff > 0 ? diff : 0), local[j] + diff); global[j] = Math.max(local[j], global[j]); } } return global[k]; } public int solveMaxProfit(int[] prices) { int res = 0; for (int i = 1; i < prices.length; ++i) { if (prices[i] - prices[i - 1] > 0) { res += prices[i] - prices[i - 1]; } } return res; } }
参考链接:http://blog.csdn.net/linhuanmars/article/details/23236995