【LeetCode & 剑指offer刷题】动态规划与贪婪法题11:121. Best Time to Buy and Sell Stock(系列)

【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)

Best Time to Buy and Sell Stock(系列)

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 (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.
Note that you cannot sell a stock before you buy one.
Example 1:
Input: [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
Not 7-1 = 6, as selling price needs to be larger than buying price.
Example 2:
Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.
 
//股票买卖问题(在指定区间仅可以一次买入,一次卖出或者不交易
//方法一:暴力法,找买入卖出数据对(a[i] a[j]),并满足i<j 时间复杂度On^2
//方法二:一次遍历,找最大值和最小值,时间复杂度On类似: Increasing Triplet Subsequence
class Solution
{
public:
    int maxProfit(vector<int>& prices)
    {
        if(prices.empty()) return 0;
        int minprice = prices[0];//初始化最低价格
        //int maxprice = prices[0];//初始化最高价格,如果这样,还需判断最低价格和最高价格的先后位置
        int maxprofit = 0;//初始化最大收益
       
        for(int p:prices) //这里用int比用auto2ms左右
        {
            if(p < minprice) minprice = p;
            else if(p-minprice > maxprofit) maxprofit = p-minprice;//计算最大收益,无需判断最高价格和最低价格的先后位置
        }
        return maxprofit;
    }
};
//方法三:转化为涨跌数组,就可以转化为最大子数组问题了,可以用分治法,略显麻烦
 
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 (i.e., buy one and sell one share of the stock multiple times).
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: [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 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.
 
 
//股票买卖问题2(可以在指定区间买卖多次不能出现连续买)
//方法:可以转成涨跌数组,将所有正数相加(或者直接判断相邻数大小,算上a[i]>a[i-1]的情况)
class Solution
{
public:
    int maxProfit(vector<int>& a)
    {
        if(a.size() <= 1) return 0;
        int max = 0;
        for(int i =1; i<a.size(); i++)
        {
            if(a[i]>a[i-1]) max += a[i]-a[i-1];
        }
        return max;
       
    }
};
 
123. Best Time to Buy and Sell Stock III (hard题)
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.
 
//问题:股票买卖问题3最多交易两次,这里一次交易指买+卖)
/* 方法:4标记(变量)法
*
  buy1 - 第一次买入后的收益,买入后收益为负数
  sell1 - 第一次卖出时的收益
  buy2 - 第二次买入后的收益
  sell2 - 第二次卖出后的收益
  保证操作的收益最大(对于buy后的收益,实质是为了最小化成本)
  (局部最优,带来全局最优,贪心法) 
*/
#include <climits>
#include <algorithm>
class Solution
{
public:
    int maxProfit(vector<int>& a)
    {
        int buy1 = INT_MIN, sell1 = 0, buy2 = INT_MIN, sell2 = 0;
        for(int ai:a)
        {
            buy1 = max(buy1, -ai); //当选择前一个数时表示不进行交易,选择后一个数时进行买入,花费ai的成本,收益变为-ai
            sell1 = max(sell1, buy1 + ai);
            buy2 = max(buy2, sell1 - ai);
            sell2 = max(sell2, buy2 + ai);
            //如何保证每次只进行一个操作?(buy1sell1不会同时操作,buy2sell2不会同时操作)
        }
        return sell2;
    }
};
 
188. Best Time to Buy and Sell Stock IV (hard)
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).
Example 1:
Input: [2,4,1], k = 2
Output: 2
Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.
Example 2:
Input: [3,2,6,5,0,3], k = 2
Output: 7
Explanation: Buy on day 2 (price = 2) and sell on day 3 (price = 6), profit = 6-2 = 4.
Then buy on day 5 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
 
//问题:股票买卖问题4最多交易k,这里一次交易指买+卖)
/*
* 方法:DP(找递推公式)
* 解释:与问题3的方法类似,每次操作与上次操作有关,确保每次操作的收益最大
  如果k >= len/2,则和问题1一样,相当于买卖次数没有限制,直接用求全局最优即可
 
buy[i][j-1]表示对于j-1天,第i次买入后的最大收益,为了节省空间可写成单变量buy
sell[i][j] 表示对于j天,第i次卖出后的最大收益
递推公式:
buy = max( buy,  sell[i-1][j-1] - a[j-1] )
 //j-1天,第i次买入(承接j-1天,第i-1次卖出,sell[i-1][j-1]),对应第j-1天不买,或者买(则减去a[j-1])
sell[i][j] = max( sell[i][j-1],  buy + a[j] ) 
//j天,第i次卖出(承接j-1天第i次买入),对应第j天不卖(sell[i][j-1])或者卖(则加上a[j])
 
 
  了解即可!!
*/
#include <algorithm>
#include <climits>
class Solution
{
public:
    int maxProfit(int k, vector<int>& a)
    {
        if(a.empty()) return 0;
       
        int n = a.size();
        if(k >= n/2) //如果买卖次数没有限制,则直接全局处理,变为问题二
        {
            int maxprofit = 0;
            for(int i = 1; i < n; i++)
            {
                if(a[i] > a[i-1]) maxprofit += a[i] - a[i-1];
            }
            return maxprofit;
        }
       
        vector<vector<int>> sell(k+1, vector<int>(n));//交易次数多开辟一段空间,以提供初值,以及索引方便
 
        for(int i = 1; i <= k; i++) //遍历交易次数,i=1~k
        {
           
            int buy = sell[i-1][0]-a[0]; //初始化
            for(int j = 1; j<n; j++) //遍历天数,j=1~n-1(天数从0开始,式中有j-1)
            {
               //buya[0]开始,sella[1]开始,错开以避免重复交易
                buy = max(buy, sell[i-1][j-1]-a[j-1]); //j-1天i次买入后的收益,(注意这里与sell[i-1][j-1]相比较,有承接性,以避免多次交易重复买卖)
                sell[i][j] = max(sell[i][j-1], buy+a[j]); //j天i次卖出之后的收益
            }
        }
        return sell[k][n-1]; //返回第k次卖出后的收益
       
    }
};
 
 
309. Best Time to Buy and Sell Stock with Cooldown
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) with the following restrictions:
  • You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
  • After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)
Example:
Input: [1,2,3,0,2]
Output: 3
Explanation: transactions = [buy, sell, cooldown, buy, sell]

 
/*
了解即可
 
问题:买卖多次,但是有冷冻期,卖出股票后要间隔一天才能再次买入
方法:动态规划
buy[i]表示在第i天之前最后一个操作是买,此时的最大收益
sell[i]表示在第i天之前最后一个操作是卖,此时的最大收益
则有递推式:
buy[i]  = max(sell[i-2] - price, buy[i-1]) i天,买入收益,第i天买(由于存在一天的冷冻期,承接i-2天的卖出收益sell[i-2])或者不买(承接buy[i-1]
sell[i] = max(buy[i-1] + price, sell[i-1]) i天,卖出收益,第i天卖(承接buy[i-1,或者不卖(承接sell[i-1]
由于i只依赖于i-1i-2,所以我们可以在O(1)的空间复杂度完成算法
*/
class Solution
{
public:
    int maxProfit(vector<int>& prices)
    {
        int buy = INT_MIN, pre_buy = 0, sell = 0, pre_sell = 0;
        for (int price:prices)
        {
            pre_buy = buy;
            buy = max(pre_sell - price, pre_buy);//i天的买入收益与i-2天的卖出收益有关
            pre_sell = sell;
            sell = max(pre_buy + price, pre_sell); //i天的卖出收益与i-1天的买入收益有关
        }
        return sell;
    }
};
 
 
 
 
 
原文地址:https://www.cnblogs.com/wikiwen/p/10229377.html