LeetCode題解: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.
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;
}