BM80 BM81买卖股票的最好时机(买卖一次、多次买卖)

1 BM80 买卖股票的最好时机(一)

描述
假设你有一个数组prices,长度为n,其中prices[i]是股票在第i天的价格,请根据这个价格数组,返回买卖股票能获得的最大收益

1.你可以买入一次股票和卖出一次股票,并非每天都可以买入或卖出一次,总共只能买入和卖出一次,且买入必须在卖出的前面的某一天;
2.如果不能获取到任何利润,请返回0;
3.假设买入卖出均无手续费;

示例1
输入:[8,9,2,5,4,7,1]
返回值:5
说明:在第3天(股票价格 = 2)的时候买入,在第6天(股票价格 = 7)的时候卖出,最大利润 = 7-2 = 5 ,不能选择在第2天买入,第3天卖出,这样就亏损7了;同时,你也不能在买入前卖出股票。

示例2
输入:[2,4,1]
返回值:2

示例3
输入:[3,2,1]
返回值:0

1.1 方法一:动态规划(O(n)、O(n))

在这里插入图片描述

  //2.动态规划
        //dp[i][0]第i天,不持股的最大收益。(不持股,可能一直没买,也可能之前已经卖出去了,或当天卖出的)
        //dp[i][1]第i天,持股的最大收益。(持股,可能是之前买的,一直没卖;也可能当天买的,此时收益为-prices[i])
        vector<vector<int>> dp(prices.size(),vector<int>(2,0));
        //第一天没买,收益为0
        dp[0][0] = 0;
        //第一天买了,收益为-prices[0]
        dp[0][1] = -prices[0];
        
        for(int i = 1; i < prices.size(); i++){
            //dp[i][0]第i天,不持股的最大收益
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
            //dp[i][1]第i天,持股的最大收益
            dp[i][1] = max(dp[i - 1][1], - prices[i]);
        }
        //return max(dp[prices.size() - 1][0],dp[prices.size() - 1][1]);
        //不用在持有和不持有之间取max,因为最大利用时,一i当时卖出了,一定不持股
        return dp[prices.size() - 1][0];
    }

复杂度分析:

时间复杂度:O(n),其中n为数组长度,遍历一次数组
空间复杂度:O(n),动态规划辅助数组的空间

1.2 方法二:贪心((O(n)、O(1)))

在这里插入图片描述

//1.贪心策略
int maxProfit(vector<int>& prices) {
        int res =0;//维持最大收益
        int Min = prices[0];//首元为初始最小值
        
        //贪心策略:MIn记录截至目前,历史最低价;;;res记录当天价格与历史最低的差值,取最大,即最大收益。
        for(int i = 1; i < prices.size(); i++){
            Min = min(Min,prices[i]);//维持最低价
            res = max(res,prices[i] - Min);//维持最大收益
        }
        return res;
    }

复杂度分析:

时间复杂度:O(n),其中nnn为数组长度,一次遍历数组;
空间复杂度:O(1),常数级变量,无额外辅助空间;

2 BM81 买卖股票的最好时机(二)

描述
假设你有一个数组prices,长度为n,其中prices[i]是某只股票在第i天的价格,请根据这个价格数组,返回买卖股票能获得的最大收益;

  1. 你可以多次买卖该只股票,但是再次购买前必须卖出之前的股票;
  2. 如果不能获取收益,请返回0;
  3. 假设买入卖出均无手续费;

示例1
输入:[8,9,2,5,4,7,1]
返回值:7
说明:
在第1天(股票价格=8)买入,第2天(股票价格=9)卖出,获利9-8=1
在第3天(股票价格=2)买入,第4天(股票价格=5)卖出,获利5-2=3
在第5天(股票价格=4)买入,第6天(股票价格=7)卖出,获利7-4=3
总获利1+3+3=7,返回7

示例2
输入:[5,4,3,2,1]
返回值:0
说明:由于每天股票都在跌,因此不进行任何交易最优。最大收益为0。

示例3
输入:[1,2,3,4,5]
返回值:4
说明:第一天买进,最后一天卖出最优。中间的当天买进当天卖出不影响最终结果。最大收益为4。

2.1 方法一:动态规划((O(n)、O(n)))

在这里插入图片描述

//dp[i][0],第i天,不持股的最大收益(可能一直没买,或之前或当天卖掉了) 
       //dp[i][1],第i天,持股的最大收益(一直没卖,或当天买入)
        int n = prices.size();
        vector<vector<int>> dp(n,vector<int>(2,0));
        dp[0][0] = 0;//第一天不持股,收益0
        dp[0][1] = -prices[0];//第一天买入,收益-prices[0]
        
        for(int i = 1; i < n; i++){
            dp[i][0] = max(dp[i-1][0],dp[i-1][1] + prices[i]);//前一天没有,今天也没买;或前一天有,今天卖了
            dp[i][1] = max(dp[i-1][1],dp[i-1][0] - prices[i]);//前一天有,今天没卖;或前一天没有,今天买了
        }
        return dp[n-1][0];
    }

复杂度分析:

时间复杂度:O(n),其中nnn为数组长度,遍历一次数组
空间复杂度:O(n),动态规划辅助数组相当于两个一维数组

2.2 贪心((O(n)、O(1)))

在这里插入图片描述

//2.贪心策略2:只要比前一天大,就立马买,不管什么区间
        int n = prices.size();
        int maxVal = 0; 
        for(int i = 1; i < n; i++){
            if(prices[i-1] < prices[i])//这就意味着,卖的当天还可以买
                maxVal += prices[i] - prices[i - 1];
        }
        return maxVal;
    }

复杂度分析:

时间复杂度:O(n),其中n为数组长度,遍历一次数组
空间复杂度:O(1),常数级变量,没有使用额外辅助空间

2.3 贪心 (自己实现)((O(n)、O(1)))

 int maxProfit(vector<int>& prices) {
        //思路一:有收益时,这一段必定是单增的,当i+1下降时,卖掉i;同时,i+1更新为新的min 
        int n = prices.size();
        int Min = prices[0];
        int maxVal = 0;
        int flag = true;//是否卖出
        int i;
        for(i = 1; i < n - 1; i++){
            flag = true;
            Min = min(prices[i],Min);
            if(prices[i] > prices[i + 1]){ //一旦价格下降,就立马卖出;并且更新Min
                 maxVal += prices[i] - Min;
                 Min = prices[i + 1];
                 flag = false;
            }    
        }
        //如果最后一次存在利润,没有卖出或者单增一直都没卖
        if(flag && prices[i] > Min) maxVal += prices[i] - Min;
        return maxVal;
    }

3 BM82 买卖股票的最好时机(三)

描述
假设你有一个数组prices,长度为n,其中prices[i]是某只股票在第i天的价格,请根据这个价格数组,返回买卖股票能获得的最大收益

  1. 你最多可以对该股票有两笔交易操作,一笔交易代表着一次买入与一次卖出,但是再次购买前必须卖出之前的股票
  2. 如果不能获取收益,请返回0
  3. 假设买入卖出均无手续费

示例1
输入:[8,9,3,5,1,3]
返回值:4
说明:
第三天(股票价格=3)买进,第四天(股票价格=5)卖出,收益为2
第五天(股票价格=1)买进,第六天(股票价格=3)卖出,收益为2
总收益为4。

示例2
输入:[9,8,4,1]
返回值:0

示例3
输入:[1,2,8,3,8]
返回值:12
说明:
第一笔股票交易在第一天买进,第三天卖出;第二笔股票交易在第四天买进,第五天卖出;总收益为12。
因最多只可以同时持有一只股票,所以不能在第一天进行第一笔股票交易的买进操作,又在第二天进行第二笔股票交易的买进操作(此时第一笔股票交易还没卖出),最后两笔股票交易同时在第三天卖出,也即以上操作不满足题目要求。

备注:
总天数不大于200000。保证股票每一天的价格在[1,100]范围内。

在这里插入图片描述
在这里插入图片描述

int maxProfit(vector<int>& prices) {
       int n = prices.size();
    
        vector<vector<int>> dp(n,vector<int>(5,-10000));//初始值为何-10000?,初始为0,运行错误
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        
        for(int i = 1; i < n; i++){
            dp[i][0] = dp[i-1][0];
            dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i]);//第一次持股
            dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i]);//第一次卖出
            dp[i][3] = max(dp[i-1][3], dp[i-1][2] - prices[i]);//第二次持股
            dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i]);//第二次卖出
        }
        //选取最大值,可以只操作一次
        return max(dp[n-1][2],max(0,dp[n-1][4]));
    }

复杂度分析:

时间复杂度:O(n),其中nnn为数组长度,只遍历一次数组
空间复杂度:O(n),动态规划二维辅助相当于5个一维数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

R-G-B

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值