面试必刷算法TOP101之买卖股票篇 TOP29

买卖股票的最好时机Ⅰ

题目来源:牛客网

1、问题描述

假设你有一个数组prices,长度为n,其中prices[i]是股票在第i天的价格,请根据这个价格数组,返回买卖股票能获得的最大收益
1.你可以买入一次股票和卖出一次股票,并非每天都可以买入或卖出一次,总共只能买入和卖出一次,且买入必须在卖出的前面的某一天
2.如果不能获取到任何利润,请返回0
3.假设买入卖出均无手续费

2、思路解析

思路:DP
确定dp数组明确其下标含义:dp[i][0]表示第i天持股所拥有的最多资金,dp[i][1]表示第i天不持股所用还有的最多资金,持有并一定是买入可能是i-1天买入i天持有
递推公式:
第i天持股有两种情况:
(1)第i天买入,持有的资金为-prices[i]
(2)第i-1天买入,第i天持有股票,持有的资金就和前一天的资金一样都是dp[i-1][0].
因为要求第i天持股的最多资金就是dp[i][0]=max(dp[i-1][0],-prices[i]);
第i天不持股有两种情况:
(1)昨天持股,今天卖出,持有的最多资金为,昨天原来持股的资金加上今天卖出的资金dp[i-1][0]+prices[i]
(2)昨天不持股,今天也不持股资金就和昨天不持股的资金一样dp[i-1][1]
因为要求第i天不持股的最多资金就是dp[i][1]=max(dp[i-1][0],dp[i-1][1]);
初始化:因为都要依赖前一天的资金,所以给dp[0][0]=-prices[0] dp[0][1]=0;
遍历顺序:从递推公式可以看出dp[i]都是有dp[i - 1]推导出来的,那么一定是从前向后遍历。

3、代码实现

class Solution {
public:
    /**
     * 
     * @param prices int整型vector 
     * @return int整型
     */
    int maxProfit(vector<int>& prices) {
        // write code h
        int len=prices.size();
        if(len<2){
            return 0;
        }
        vector<vector<int>> dp(len,vector<int>(2));
        dp[0][0]=-prices[0];
        dp[0][1]=0;
        for(int i=1;i<len;i++){
            dp[i][0]=max(dp[i-1][0],-prices[i]);
            dp[i][1]=max(dp[i-1][0]+prices[i],dp[i-1][1]);
        }
    return dp[len-1][1];
        
    }
};

买卖股票的最好时机Ⅱ

题目来源:牛客网

1、问题描述

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

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

2、思路解析

思路:DP
这道题和之前的不同之处就是多次买入卖出
确定dp数组明确其下标含义:dp[i][0]表示第i天持股所拥有的最多资金,dp[i][1]表示第i天不持股所用还有的最多资金,持有并一定是买入可能是i-1天买入i天持有
递推公式:
第i天持股有两种情况:
(1)第i天买入,持有的资金为前一天不持有股票资金减去当天买股票的资金dp[i-1][1]-prices[i]
(2)第i-1天买入,第i天持有股票,持有的资金就和前一天的资金一样都是dp[i-1][0].
因为要求第i天持股的最多资金就是dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i]);
第i天不持股有两种情况:
(1)昨天持股,今天卖出,持有的最多资金为,昨天原来持股的资金加上今天卖出的资金dp[i-1][0]+prices[i]
(2)昨天不持股,今天也不持股资金就和昨天不持股的资金一样dp[i-1][1]
因为要求第i天不持股的最多资金就是dp[i][1]=max(dp[i-1][0],dp[i-1][1]);
初始化:因为都要依赖前一天的资金,所以给dp[0][0]=-prices[0] dp[0][1]=0;
遍历顺序:从递推公式可以看出dp[i]都是有dp[i - 1]推导出来的,那么一定是从前向后遍历。

3、代码实现

class Solution {
public:
    
    /**
     * @param prices int整型vector 
     * @return int整型
     */
    int maxProfit(vector<int>& prices) {
        
        // write code here
        int len=prices.size();
        if(len<2){
            return 0;
        }
        vector<vector<int>> dp(len,vector<int>(2,0));
        dp[0][0]=-prices[0];//假设卖出去了就是持股或者
        dp[1][0]=0;
        for(int i=1;i<len;i++){
            dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i]);//(昨天买入今天还继续持股资金还是和昨天一样,今天买入昨天持有的资金减去今天买股票的资金)
            dp[i][1]=max(dp[i-1][0]+prices[i],dp[i-1][1]);//(昨天持股今天卖股票,今天不买股票什么都不做)
        }
        return dp[len-1][1];
    }
};

买卖股票的最好时机Ⅲ

题目来源:牛客网

1、问题描述

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

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

2、思路解析

思路:DP
对于每一天都有不同的可能:(1)没有任何人操作 (2)第一次持有(当前买入持有或者前面买入就持有) (3)第一次卖出或者第一次已经卖出(4)第二次持有(当前买入持有或者前面买入就持有) (5)第二次卖出或者第二·次已经卖出
确定dp数组 及下边含义:dp数组是一个宽度为5的数组
dp[i][0]:表示第i天没有操作所以就和前一天没有操作的资金一样
dp[i][1]:第一次持有如果是当天买入就是前一天没有操作的减去买股票的资金或者当天没有买入而是前边买入的当天只不过是持有的资金就和前一天相同max(dp[i-1][0]-prices[i],dp[i-1][1])
dp[i][2]:第一次卖出或者第一次已经卖出。当天卖出紫金就是前一天持股的资金加上卖出股票的资金或者就是前边已经卖出了当天的资金就是前一天第一次卖出或者第一次已经卖出的资金了max(dp[i-1][2],dp[i-1][1]+prices[i])
后边的两种情况和前边的这两种情况相同
直接给出递推公式
dp[i][3]=max(dp[i-1][2]-prices[i],dp[i-1][3])
dp[i][4]=max(dp[i-1][4],dp[i-1][3]+prices[i])
初始化:
第0天没有操作,这个最容易想到,就是0,即:dp[0][0] = 0;
第0天做第一次买入的操作,dp[0][1] = -prices[0];
第0天做第一次卖出的操作,这个初始值应该是多少呢?
首先卖出的操作一定是收获利润,整个股票买卖最差情况也就是没有盈利即全程无操作现金为0,从递推公式中可以看出每次是取最大值,那么既然是收获利润如果比0还小了就没有必要收获这个利润了。所以dp[0][2] = 0;
第0天第二次买入操作,初始值应该是多少呢?第一次还没买入呢,怎么初始化第二次买入呢?
第二次买入依赖于第一次卖出的状态,其实相当于第0天第一次买入了,第一次卖出了,然后在买入一次(第二次买入),那么现在手头上没有现金,只要买入,现金就做相应的减少。所以第二次买入操作,初始化为:dp[0][3] = -prices[0];同理第二次卖出初始化dp[0][4] = 0;

代码实现

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 两次交易所能获得的最大收益
     * @param prices int整型vector 股票每一天的价格
     * @return int整型    
     */

    int maxProfit(vector<int>& prices) {
        // write code here
        int len=prices.size();
        if(len<2){
            return 0;
        }
        vector<vector<int>>dp(len,vector<int>(5,0));
   
        dp[0][1]=-prices[0];
     
        dp[0][3]=-prices[0];
     
        for(int i=1;i<len;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 dp[len-1][4];
    }
};

买卖股票的最好时机Ⅳ

题目来源:牛客网

1、问题描述

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

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

2、思路解析

思路:DP
思路和上一题差不多只不过就是多买几次多卖几次就行了
思路:DP
对于每一天都有不同的可能:(1)没有任何人操作 (2)第一次持有(当前买入持有或者前面买入就持有) (3)第一次卖出或者第一次已经卖出(4)第二次持有(当前买入持有或者前面买入就持有) (5)第二次卖出或者第二·次已经卖出。。。。。。。。。。。。。。
(n-1)第n次持有(当前买入持有或者前面买入就持有) (n)第n次卖出或者第n次已经卖出
确定dp数组 及下边含义:dp数组是一个宽度为5的数组
dp[i][0]:表示第i天没有操作所以就和前一天没有操作的资金一样
dp[i][1]:第一次持有如果是当天买入就是前一天没有操作的减去买股票的资金或者当天没有买入而是前边买入的当天只不过是持有的资金就和前一天相同max(dp[i-1][0]-prices[i],dp[i-1][1])
dp[i][2]:第一次卖出或者第一次已经卖出。当天卖出紫金就是前一天持股的资金加上卖出股票的资金或者就是前边已经卖出了当天的资金就是前一天第一次卖出或者第一次已经卖出的资金了max(dp[i-1][2],dp[i-1][1]+prices[i])
后边的情况和前边的这两种情况相同
直接给出递推公式直接循环处理就行了
初始化:
第0天没有操作,这个最容易想到,就是0,即:dp[0][0] = 0;
第0天做第一次买入的操作,dp[0][1] = -prices[0];
第0天做第一次卖出的操作,这个初始值应该是多少呢?
首先卖出的操作一定是收获利润,整个股票买卖最差情况也就是没有盈利即全程无操作现金为0,从递推公式中可以看出每次是取最大值,那么既然是收获利润如果比0还小了就没有必要收获这个利润了。所以dp[0][2] = 0;
第0天第二次买入操作,初始值应该是多少呢?第一次还没买入呢,怎么初始化第二次买入呢?
第二次买入依赖于第一次卖出的状态,其实相当于第0天第一次买入了,第一次卖出了,然后在买入一次(第二次买入),那么现在手头上没有现金,只要买入,现金就做相应的减少。所以第二次买入操作,初始化为:dp[0][3] = -prices[0];同理第二次卖出初始化dp[0][4] = 0;

3、代码实现

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param prices int整型vector 
     * @param k int整型 
     * @return int整型
     */
    int maxProfit(vector<int>& prices, int k) {
          // write code here
        int len=prices.size();
        vector<vector<int>> dp(len,vector<int>(2*k+1,0));
       for(int i=1;i<2*k;i+=2){
           dp[0][i]=-prices[0];
       }
        for(int i=1;i<len;i++){
            for(int j=1;j<2*k;j+=2){
            dp[i][j]=max(dp[i-1][j],dp[i - 1][j-1]-prices[i]);  
            dp[i][j+1]=max(dp[i-1][j+1],dp[i-1][j]+prices[i]); 
            }
        }
        return dp[len-1][2*k];
    }
};
  • 19
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

自首的小偷

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

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

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

打赏作者

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

抵扣说明:

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

余额充值