leeticode 121.122.123. Best Time to Buy and Sell Stock

问题一

Say you have an array for which the ith element is the price of a given stock on day i.

If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.

先计算数组每个相邻成员之差,将其存为另一个数组。然后计算该数组的最大子数组之和。具体用动态规划法。

int count_max(const vector<int> &vec)
{
	vector<int>::const_iterator iter = vec.begin();
	int sum = 0, max = 0;
	while (iter != vec.end())
	{
		sum += *iter;
		if (sum > max)
			max = sum;
		if (sum < 0)
			sum = 0;
		iter++;
	}
	return max;
}

int maxProfit(vector<int>& prices) 
{
	int length = prices.size();
	if (length == 0 || length == 1)
		return 0;
	vector<int> price_dif(length - 1, 0);
	for (int i = 0; i < length - 1; ++i)
		price_dif[i] = prices[i + 1] - prices[i];
	int res = count_max(price_dif);
	return res;
}
方法二,不管你抛出股票的时机为何时,在你收入股票的时候绝对是前面时间里面股票价格最低的时候。

该方法用一个minPrice维护一个目前最低股票价格,每遍历一个新的价格就更新minPrice和该新价格和minPrice之差。

class Solution {
public:
int maxProfit(vector<int> &prices) {
    int maxPro = 0;
    int minPrice = INT_MAX;
    for(int i = 0; i < prices.size(); i++){
        minPrice = min(minPrice, prices[i]);
        maxPro = max(maxPro, prices[i] - minPrice);
    }
    return maxPro;
}
问题二

现在没有只能一次股票买卖的限定,求出最大收益。

很简单,我们只需买会增值的股票就好,反映到程序里面就是累加每次相邻两天股票涨价的价格,贪心算法。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        	int length = prices.size();
	if (length == 0 || length == 1)
		return 0;
	int temp=0;
	int res=0;
	for (int i = 0; i < length - 1; ++i)
	{
		temp = prices[i + 1] - prices[i];
		if (temp>=0)
		    res+=temp;
	}
	return res;
    }
};

问题三

改为允许买卖两次股票。

本打算这样做:

for(从第一天到最后一天)

{

以当前天为界限,将所有天数分成两个子数列,分别对他们调用问题1里面的算法,求得目前划分法下的最大收益。

将这个最大收益与历史最大收益比较max_profit_all = max( max_profit_all , ( max_profit(1) + max_profit(2) ) )。

}

return  max_profit_all;

但是系统提示时间复杂度过高。分析程序,外围的for进行N次,然后每次循环里面计算两个字数组的最大profit应该是2*O(n)的时间复杂度,总的来说是O(n*n),确实有点那啥。

究其原因,在于每个for里面都要“重新”计算一次之前已经计算过一部分的max_profit

回归到第一个问题,只能进行一次买卖的限定条件下,我们通过动态规划法来求得结果,

什么是动态规划?

每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的

比如我们在计算一个长为5的数列最大收益时候,其实我们在for循环里面已经把2/3/4/5天的最大收益全计算出来了,只是没有将他们存起来而已。

进而回到第三个问题,不是说了要求出N种分割数组方法的对应max_profit吗?好,用问题1里面的方法求顺序数组的最大收益

class Solution {
public:
int maxProfit(vector<int> &prices) {
    int maxPro = 0;
    int minPrice = INT_MAX;
    for(int i = 0; i < prices.size(); i++){
        minPrice = min(minPrice, prices[i]);
        maxPro = max(maxPro, prices[i] - minPrice);
        /*max_profit_1.push_back(maxPro)*/
    }
    return maxPro;
}

不同的是,我们在每一个for里面都将目前的最大profit推进vec中,这不就是1,2/1,2,3/1,2,3,4/1,2,3,4,5/...../1,2,3,,,,,,n 子数组分别的最大收益吗。

同样方法,计算1,2,3,,,,,,n / 2,3,,,,,,n / 3,4,,,,,,n / .......  /n-1,n这些子数组的最大收益。

目前所花时间应该是2*O(N)。

然后计算两个数组对应位置上元素最大的和就可以了,时间复杂度O(N)。

总的时间花费为 3 * O(n)。

下面贴上问题三的完整代码:

class Solution {
public:
int smaller(int a, int b)
{
	return a < b ? a : b;
}
int bigger(int a, int b)
{
	return a > b ? a : b;
}
int maxProfit(vector<int>& prices) {
	int length = prices.size();
	vector<int> profit1(length,0);
	vector<int> profit2(length, 0);
	int max_profit = 0;
	int low_price = INT_MAX;
	for (int i = 0; i < length; ++i)
	{
		low_price = smaller(low_price, prices[i]);
		max_profit = bigger(max_profit, prices[i] - low_price);
		profit1[i] = max_profit;
	}
	max_profit = 0;
	int high_price = 0;
	for (int i = length-1; i >= 0; --i)
	{
		high_price = bigger(high_price, prices[i]);
		max_profit = bigger(max_profit, high_price-prices[i]);
		profit2[i] = max_profit;
	}
	int res = 0;
	for (int i = 0; i < length; ++i)
		res = bigger(res, (profit1[i] + profit2[i]));
	return res;
}
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值