LeetCode题解:Best Time to Buy and Sell Stock(致富有望???)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jining11/article/details/84801595

题目

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

Example 1:

Input: [3,3,5,0,0,3,1,4]
Output: 6
Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.
Example 2:

Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
engaging multiple transactions at the same time. You must sell before buying again.
Example 3:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

分析

其实本质上就是给你一串数字,让你找出可以找出的一对相差最大的两个数之间的差值,并且要求较小的数在较大的数之前出现,对应的投资操作就是低位买入高位卖出,当然题目里还有个要求是可以进行两次交易,也就是找出两个这样的数对并使它们的和最大。

第一次动态规划

思路还是很简单的,就是建立在这样的思想上,[i,j]区域内的解,一定是所有以[i,j]内的数字k对应的值为结尾,以[i,k]内最小值为开头,这样的一个数字对的差值。所以动态规划只需要求出任意[i,j]区域内的最小值,之后使用遍历求解即可。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
    int maxProfit(vector<int>& prices) {
    	int n = prices.size();
    	int end = 0;//端点的末端
    	//P[i][j]的含义为从i时刻到j时刻,股票市值的最小值
        vector<vector<int>> P(n, vector<int>(n, 0));
        //length的含义为动态规划时区间的长度,从小到大变化
        //将i==j的点初始化为prices[i]对应的值
        for (int i = 0; i < n; i++) {
        	P[i][i] = prices[i];
        }
        for (int length = 1; length < n; length++) {
        	//start为每个区间端点的起始点的位置
        	for (int start = 0; start+length < n-1; start++) {
        		end = start+length;
        		P[start][end] = min(P[start][end-1], prices[end]);
        	}
        }
        int max = 0, max1 = 0, max2 = 0;
        for (int i = 1; i < n; i++) {
        	if (prices[i]-P[0][i-1] > max) {
        		max = prices[i]-P[0][i-1];
        	}
        }
        //分割循环
        for (int split = 1; split < n-2; split++) {
        	max1 = 0;
        	max2 = 0;
        	for (int k = 1; k <= split; k++) {
        		if (prices[k]-P[0][k-1] > max1) {
        			max1 = prices[k]-P[0][k-1];
        		}
        	}
        	for (int k = split+2; k < n; k++) {
        		if (prices[k]-P[split+1][k-1] > max2) {
        			max2 = prices[k]-P[split+1][k-1];
        		}
        	}
        	if (max1+max2 > max) {
        		max = max1+max2;
        	}
        }
        return max;
    }
};

int main() {
	int a[] = {7,6,4,3,1};
	std::vector<int> v(a, a+5);
	Solution s;
	cout << s.maxProfit(v);
	return 0;
}

这是我第一次见到这种错误,最后一个样例太大导致。。。内存空间不够???看来是表示方式有问题,那到底应该怎么表示好呢?

让我们冷静一下,重新审视一下刚才的解法,你会发现你浪费了许多的空间,因为你所需要计算的,只有左端点固定为0的P[0][i]和右端点固定为n-1的P[i][n-1],换句话说,本来只需要2*n的空间,我却使用了n^2的空间。

第二次动态规划

本质上还是一样的,不过没有浪费空间。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
    int maxProfit(vector<int>& prices) {
		if (prices.size() == 0) {
			return 0;
		}
    	int n = prices.size();
		//Left[i]表示从0到i的最大收益,Right[j]表示从j到n-1的最大收益
    	vector<int> Left(n, 0);
		vector<int> Right(n, 0);
		for (int i = 1, mmin = prices[0]; i < n; i++) {
			if (prices[i] < mmin) {
				mmin = prices[i];
			}
			Left[i] = max(Left[i-1], prices[i]-mmin);
		}
		for (int i = n-2, mmax = prices[n-1]; i >= 0; i--) {
			if (prices[i] > mmax) {
				mmax = prices[i];
			}
			Right[i] = max(Right[i+1], mmax-prices[i]);
		}
		int result = Left[n-1];
		for (int k = 1; k < n-2; k++) {
			if (result < Left[k]+Right[k+1]) {
				result = Left[k]+Right[k+1];
			}
		}
		return result;
    }
};

int main() {
	int a[] = {1,2,3,4,5};
	std::vector<int> v(a, a+5);
	Solution s;
	cout << s.maxProfit(v);
	return 0;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/jining11/article/details/84801595