题目
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;
}