1. 程式人生 > >LeetCode題解:Best Time to Buy and Sell Stock(致富有望???)

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

在這裡插入圖片描述