LeetCode 123. Best Time to Buy and Sell Stock III

               这道题是LeetCode 121 和 122 的升级版,题意也差不多,也是给出一个数组,每个元素代表每天买入卖出石头的价格,不能在同一天买入与卖出,要先卖出已有的石头才能重新买入,求最大利润。这次限制买入卖出的次数为2。

          这道题比较简单的方法是枚举每个i,即0 <= i <= n-1 , 分别求出[0,i] 和 [i+1, n-1] 两个区间各买卖一次的最大利润,求和。这样和的最大值就是最大利润。时间复杂度为O(n2)。

          但这样会超时。于是还有另外一种动态规划的做法,我们可用g[i] 表示 区间[ 0, i] 买卖最多一次的最大值,用f[i] 表示区间[ i, n-1] 买卖最多一次的最大值。对于g[i] , f[i] 有递推公式:

         当 i = 0 时, g[i] = 0 ;

         当  1 <= i <= n-1 时, g[i] = max(g[i-1], prices[i] - ming) , 其中ming 为区间[0, i-1] 中prices的最小值。

         当 i = n-1 时, f[i] = 0 ;

         当 0 <= i <= n-2 时,  f[i] = max(g[i+1], maxf - prices[i]), 其中maxf 为区间[i+1, n-1] 中prices 的最大值。

         计算g[i] , f[i] 的时间复杂度为O(n)。

         则利润的最大值要么是g[n-1], 要么是g[i] + f[i+1] 的最大值。计算的时间复杂度为O(n)。

         所以总的复杂度为O(n),代码如下:

# include <iostream>
# include <cstdio>
# include <cstring>
# include <vector>
using namespace std ;

const int maxn = 100000 + 50 ;
const int INF = 10000000 ;
int f[maxn], g[maxn] ;

class Solution {
public:
    int maxProfit(vector<int>& prices) ;
};

int Solution::maxProfit(vector<int>& prices) {
	if (prices.size() == 0) return 0 ;
	
	memset(f, 0, sizeof(f)) ;
	memset(g, 0, sizeof(g)) ;
	
	int n = prices.size() ;
	int maxf = -INF ;
	int ming = INF ;
	
	g[0] = 0 ;
	ming = prices[0] ;
	for (int i=1; i<n; i++) {
		g[i] = max(g[i-1], prices[i]-ming) ;
		if (prices[i] < ming) ming = prices[i] ;
	}
	f[n-1] = 0 ;
	maxf = prices[n-1] ;
	for (int i=n-2; i>=0; i--) {
		f[i] = max(f[i+1], maxf-prices[i]) ;
		if (prices[i] > maxf) maxf = prices[i] ;
	}
	int ans = max(g[n-1], f[0]) ;
	for (int i=0; i<n-1; i++) {
		ans = max(ans, g[i]+f[i+1]) ;
	}
//	cout << g[2] << " " << f[4] << endl ;
	return ans ;	
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值