您的位置:首页 > 编程语言 > C语言/C++

leetcode_[python/C++]_121/122/123/188.Best Time to Buy and Sell Stock I/II/III/IV

2016-11-21 20:49 721 查看
121. 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.

122. Best Time to Buy and Sell Stock II

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 as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

123. Best Time to Buy and Sell Stock III

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

188. Best Time to Buy and Sell Stock IV

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 k transactions.

Note:

You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

[分析]

首先这四道题是类似的题型,逐步深入

第一道题:求一次买入卖出的最大收益

第二道题:可以买入卖出任意多次,求最大收益

第三道题:限制买入卖出次数最多为2次,求最大收益

第四道题:限制买入卖出次数最多为k次,求最大收益

第一道题:

解法1:

int maxProfit(vector<int>& prices) {
int size = prices.size();
if(size == 0)
return 0;
int low = prices[0];
int high = prices[0];
int temp_low=low;
for(int i=1;i<size;i++)
{
if(prices[i]-temp_low>=high-low)
{
low = temp_low;
high = prices[i];
}
else if(prices[i]>high)
high = prices[i];
else if(prices[i]<=low)
{
if(prices[i]<=temp_low) temp_low = prices[i];
}

}
if(high-low<=0)
return 0;
else
return high - low;
}


解法2:

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


或者:

int maxProfit(vector<int>& prices) {
int minPrice = INT_MAX;
int maxProfit = 0;

for (int currPrice : prices){
if (currPrice < minPrice) minPrice = currPrice;
else maxProfit = max(currPrice - minPrice, maxProfit);
}

return maxProfit;
}


解法3(动态规划):

int maxProfit(vector<int>& prices) {
int Nsize = prices.size();
int sumCurrent = 0;
int sumIncrease = 0;

for(int i = 1; i < Nsize; i++)
{
sumIncrease = sumIncrease + prices[i] - prices[i-1];
if(sumIncrease > sumCurrent) sumCurrent = sumIncrease;
if(sumIncrease < 0) sumIncrease = 0;

}
return sumCurrent;
}


注:第三种解法效率最高

第二道题:

解法1:

从前往后(python):

def maxProfit(self, prices):
return sum(max(prices[i + 1] - prices[i], 0) for i in range(len(prices) - 1))


从前往后(C++):

int maxProfit(vector<int>& prices) {
int size = prices.size();
if ( size == 0 || size == 1 ) return 0;
int low = prices[0] , max_profit = 0;
for ( int p : prices ){
if ( p > low ) max_profit += p - low;
low = p;
}
return max_profit;
}


从前往后2(C++):

int maxProfit(vector<int>& prices) {
if ( prices.size() == 0 ) return 0;
int max_profit = 0;
for ( int i = 0 ; i < prices.size() - 1 ; i ++ ){
max_profit += prices[i+1] > prices[i] ? prices[i+1] - prices[i] : 0;
}
return max_profit;
}


解法2:

从后往前:

int maxProfit(vector<int>& prices) {
int size = prices.size();
if ( size == 0 || size == 1 ) return 0;
int high = prices[size - 1] , max_profit = 0;
for ( int i = size - 2 ; i >= 0 ; i -- ){
if ( prices[i] > prices[i+1] ){
max_profit += high - prices[i+1];
high = prices[i];
}
}
if ( prices[0] < high ) max_profit += high - prices[0];
return max_profit;
}


两种思路都是O(n) time O(1) space,效率一样

第三道题:

思路:

找出从0到i的最大收益profit[i]

找出从i到size-1的最大收益profit[i]

之和求最大值

解法1:

O(2n) time O(1) space

int maxProfit(vector<int>& prices) {
int size = prices.size();
if( size <= 1 ) return 0;
int profit[size];
memset(profit,0,sizeof(profit));
int max_profit = 0;
int Mins = prices[0];
for( int i = 1 ; i < size ; i ++ ){
if( prices[i] - Mins > max_profit ) max_profit = prices[i] - Mins;
if( prices[i] < Mins ) Mins = prices[i];
profit[i] = max_profit;
}
int max_profit_r = 0;
int Maxs = prices[size - 1] ;
for( int i = size - 1 ; i >= 0 ; i-- ){
if( profit[i] + Maxs - prices[i] > max_profit_r ) max_profit_r = profit[i] + Maxs - prices[i];
if( Maxs < prices[i] ) Maxs = prices[i];
}
return max_profit_r;

}


解法2:

O(n) time O(1) space

int maxProfit(vector<int>& prices) {
int size = prices.size();
if( size <= 1 ) return 0;
int sel_1 = 0 , sel_2 = 0;
int buy_1 = -prices[0], buy_2 = -prices[0];
int profit = 0 ;
for( int i = 0 ; i < size ; i ++ ) {
int last_sel = sel_1;
sel_1 = max( sel_1 , prices[i] + buy_1 );
buy_1 = max( -prices[i] , buy_1 );
sel_2 = max( sel_2 , prices[i] + buy_2 );
buy_2 = max( last_sel - prices[i] , buy_2 );
profit = max( sel_1 , sel_2 );
}
return profit;

}


注:这两种解法效率相当

第四道题:

这道题有一个注意的地方就是当k>=prices.size()/2时候,证明我们可以随意买入卖出,直接累加即可

解法1:

O(kn) space O(n) time

int maxProfit(int k, vector<int>& prices) {
// f[k, ii] represents the max profit up until prices[ii] (Note: NOT ending with prices[ii]) using at most k transactions.
// f[k, ii] = max(f[k, ii-1], prices[ii] - prices[jj] + f[k-1, jj]) { jj in range of [0, ii-1] }
//          = max(f[k, ii-1], prices[ii] + max(f[k-1, jj] - prices[jj]))
// f[0, ii] = 0; 0 times transation makes 0 profit
// f[k, 0] = 0; if there is only one price data point you can't make any money no matter how many times you can trade
if (prices.size() <= 1) return 0;
if ( k > prices.size()/2 ){
int max_profit = 0;
for( int i = 1 ; i < prices.size() ; i ++ ){
max_profit += max( prices[i] - prices[i-1] , 0 );
}
return max_profit;
}
else {

int maxProf = 0;
vector<vector<int>> f(k+1, vector<int>(prices.size(), 0));
for (int kk = 1; kk <= k; kk++) {
int tmpMax = f[kk-1][0] - prices[0];
for (int ii = 1; ii < prices.size(); ii++) {
f[kk][ii] = max(f[kk][ii-1], prices[ii] + tmpMax);
tmpMax = max(tmpMax, f[kk-1][ii] - prices[ii]);
maxProf = max(f[kk][ii], maxProf);
}
}
return maxProf;
}
}


解法2:

O(kn) space O(n) time

动态规划(比上面的快一点)

int maxProfit(int k, vector<int>& prices) {
int n = prices.size();
if(k == 0 || n <= 1){
return 0;
}
if (k >=  n/2) {
int maxPro = 0;
for (int i = 1; i < n; i++) {
if (prices[i] > prices[i-1])
maxPro += prices[i] - prices[i-1];
}
return maxPro;
}
vector<vector<int>> dp(k + 1, vector<int>(n + 1, 0));
for(int i = 1; i <= k; ++i){
int tmpMax = dp[i - 1][0] - prices[0];
for(int j = 1; j <= n; ++j){
dp[i][j] = max(dp[i][j - 1], tmpMax + prices[j - 1]);
tmpMax = max(tmpMax, dp[i - 1][j - 1] - prices[j - 1]);
}
}
return dp[k]
;
}


解法3:

O(n) space O(n) time

比上面的快点

int maxProfit(int k, vector<int>& prices) {
int n = prices.size();
if (k>=n/2) {
int sum = 0;
for(int i=1; i<n; i++){
if(prices[i] > prices[i-1]){
sum += prices[i] - prices[i-1];
}
}
return sum;
}
vector<int> buy(k+1, INT_MIN), sale(k+1, 0);
for(int i=0; i<n; i++){
for(int j=1; j<=k; j++){
buy[j] = max(buy[j], sale[j-1]-prices[i]);
sale[j] = max(sale[j], buy[j] + prices[i]);
}
}
return sale[k];
}


解法4:

网上的一种解法,利用heap,stack

O(klogn)time ( 最快 )

贴出来一起学习

int maxProfit(int k, vector<int>& prices) {

// Step 1: Find out all profit opportunities
vector<int> profits;
stack<pair<int, int>> vps; // valley-peak pairs

int v;
int p = -1;
for (;;) {
// find next valley-peak pair
for (v = p+1; (v+1 < prices.size()) && (prices[v] >= prices[v+1]); ++v);
for (p = v  ; (p+1 < prices.size()) && (prices[p] <= prices[p+1]); ++p);

if (v == p) { // v==p means that both v and p reach the end of the array
break;
}

// Consider two transactions (v1, p1) (back of the stack) and (v2, p2) (the new-found).
// If prices[v1] >= prices[v2],
// it is meaningless to combine the two transactions.
// Save of profit of (v1, p1), and pop it out of the record.
while ((!vps.empty()) && (prices[v] <= prices[vps.top().first])) {
profits.push_back(prices[vps.top().second] - prices[vps.top().first]);
vps.pop();
}

// If prices[v1]<prices[v2] and prices[p1]<prices[p2],
// then it is meaningful to combine the two transactions
// update (v1, p1) to (v1, p2), and save the profit of (v2, p1)
while ((!vps.empty()) && (prices[p] >= prices[vps.top().second])) {
profits.push_back(prices[vps.top().second] - prices[v]);
v = vps.top().first;
vps.pop();
}

// save the new-found valley-peak pair
vps.emplace(v, p);
}

// save all remaining profits
while (!vps.empty()) {
profits.push_back(prices[vps.top().second] - prices[vps.top().first]);
vps.pop();
}

// Step 2: Calculate the k highest profits
int ret;
if (profits.size() <= k) {
ret = accumulate(profits.begin(), profits.end(), 0);
} else {
nth_element(profits.begin(), profits.end() - k, profits.end());
ret = accumulate(profits.end() - k, profits.end(), 0);
}
return ret;
}


总结:这四道题虽然不断变化,但是基本的思想是一致的,而且,基本都是能够O(n) time的解法解决
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息