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

【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   i th   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 时间复杂度 O n^2
// 方法二:一次遍历,找最大值和最小值,时间复杂度 O n )类似: 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 比用 auto 2ms 左右
        {
            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   i th   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   i th   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 );
            // 如何保证每次只进行一个操作? (buy1 sell1 不会同时操作, buy2 sell2 不会同时操作 )
        }
        return sell2 ;
    }
};
 
188 .   Best Time to Buy and Sell Stock IV (hard)
Say you have an array for which the   i th   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)
            {
                //buy a[0] 开始, sell a[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   i th   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-1 i-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 ;
    }
};
 
 
 
 
 

 

posted @ 2019-01-06 16:51 wikiwen 阅读( ...) 评论( ...) 编辑 收藏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值