Best Time to Buy and Sell Stock III O(n) 求解方法

leetcode的题目:http://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/

leetcode的题目都很简练,但是很有趣,认真地做吧。

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

a. 对于输入为n,最多可以买卖两次,求最大的盈利。

b. 买两次的收益通常比买一次来的大。

c. 对于输入规模为n,当n>=4时可以将n分为两部分,且分类的方法有n-3种。每份的最少个数为2。因为n个元素,总共有n-1条缝隙可以划分,又最左或最右至少要有两个元素,所以n-1-2 = n-3 种。

d. 求得划分一次(买卖两次)的每种划分的最大盈利,和不划分的最大盈利,即得到最大的盈利。

  max_profit = max{买卖两次(划分一次),买卖一次(不进行划分)}

e. 定义状态矩阵dp_be[i], 表示以0为起点,i为终点的子串的最大盈利。

	dp_be[0] = 0;
	int i, max_profit = 0, cur_min = prices[0];
	for(i = 1; i < len; i++) {
		max_profit = max(max_profit, prices[i]-cur_min);
		cur_min = min(cur_min, prices[i]);
		dp_be[i] = max_profit; // 在i时卖出的最大收益
	}

f. 定义状态矩阵dp_af[i],表示以i为起点,n-1(最后元素)为终点的子串的最大盈利

	max_profit = 0; 
	int cur_max = prices[len-1];
	for(i = len-2; i >= 0; i--) {
		max_profit = max(max_profit, cur_max-prices[i]);
		cur_max = max(cur_max, prices[i]);
		dp_af[i] = max_profit;
	}

g. 由此可得,对于以i为划分点,将n个元素分成两个子串,要求两个子串之和最大,根据贪心算法思想,要求每个子串都去的最大值。对i从1到n-3循环得到最大值。

		// 放入只买一次的最大值
		int max = dp_be[len-1];
		// 在同一天卖了再买是没有意义的
		// 求两个数组和的最大值
		for(i = 1; i < len-1; i++) {
			if(dp_be[i]+dp_af[i+1] > max)
				max = dp_be[i]+dp_af[i+1];
		}

主要:dp_be[i]表示0开始,i结束的子串的最大盈利,所以它对应的尾部子串为dp_af[i+1],表示以i+1开始,n-1为终点的子串的最大盈利。

h. 代码

int Solution::maxProfit2(vector<int> &prices) {
	int len = prices.size();
	if(len < 2)
		return 0;
	int *dp_be = new int[len]; // 记录前向最大
	int *dp_af = new int[len]; // 记录后向最大
	dp_be[0] = 0;
	int i, max_profit = 0, cur_min = prices[0];
	for(i = 1; i < len; i++) {
		max_profit = max(max_profit, prices[i]-cur_min);
		cur_min = min(cur_min, prices[i]);
		dp_be[i] = max_profit; // 在i时卖出的最大收益
	}
	dp_af[len-1] = 0;
	max_profit = 0; 
	int cur_max = prices[len-1];
	for(i = len-3; i >= 0; i--) {
		max_profit = max(max_profit, cur_max-prices[i]);
		cur_max = max(cur_max, prices[i]);
		dp_af[i] = max_profit;
	}
	if(len == 2)
		return dp_be[len-1];
	else {
		// 放入只买一次的最大值
		int max = dp_be[len-1];
		// 在同一天卖了再买是没有意义的
		// 求两个数组和的最大值
		for(i = 1; i < len-1; i++) {
			if(dp_be[i]+dp_af[i+1] > max)
				max = dp_be[i]+dp_af[i+1];
		}
		return max;
	}
}

 

i. 画个图说明以下

 

 

 

 

posted on 2014-04-23 22:35  themo  阅读(204)  评论(0编辑  收藏  举报

导航