股票的最佳抛售时机问题的入门学习

股票抛售的最佳时机

参考:代码随想录 (programmercarl.com)

股票的抛售的最佳时机是动态规划问题中的一类题目,今天笔者就记录一下自己对于这类问题的看法与见解

股票问题:121. 买卖股票的最佳时机 - 力扣(LeetCode)

我们通过动态规划五部曲来解决这道问题

  • 确定dp数组的含义与其下标的含义

    • 我们分析题目意思可以知道因为股票存在两种状况一种是持有,另一种是不持有。所以我们定义一个二维数组来分别表示不同的状况。

      dp[i ][1]表示第i天持有股票所得最多现金

      dp[i][0]表示第i天不持有股票所得最多现金

  • 确定递推公式

    • 我们发现每一个可以每一个位置可以从两个方向推出来。

      第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i - 1][0] : dp[i][0] = fmax(dp[i-1][0], dp[i-1][1] + prices[i]);

      第i天买入股票,所得现金就是买入今天的股票后所得现金即:dp[i][1] = fmax(-prices[i], dp[i-1][1])

  • dp数组初始化

    • 我们应该初始化dp数组的dp[0][0]和dp[0][1]。一个初始化为0,另一个初始化为-price[0]。
  • 遍历顺序

    • 我们应当从前向后进行一个遍历,这样就可以实现一个 遍历
  • 推导dp数组

int maxProfit(int* prices, int pricesSize) {
    int dp[pricesSize][2];
    dp[0][0] = 0;
    dp[0][1] = -prices[0];
    for (int i = 1; i < pricesSize; i++) { //进行一个推导
        dp[i][0] = fmax(dp[i-1][0], dp[i-1][1] + prices[i]);
        dp[i][1] = fmax(-prices[i], dp[i-1][1]);
    }
    if (dp[pricesSize-1][0] > dp[pricesSize - 1][1]) {
        return dp[pricesSize -1][0];
    }
    else {
        return dp[pricesSize -1][1];
    }
}

这道题目也可以用贪心算法实现

我们只要找出局部最优就可以实现,我们每次找最低的,然后计算每一次售卖可以得到的利润,从而得到一个最大利润。

int maxProfit(int* prices, int pricesSize) {
    int low  = prices[0];
    int result = 0;
    for (int i = 0; i < pricesSize; i++) {
        low = fmin(low, prices[i]); //
        result = fmax(result, prices[i] - low);
    }
    return result;
}

之后我们在将问题提升一下难度

122. 买卖股票的最佳时机 II - 力扣(LeetCode)

这次引入了多次售卖,因此我们的dp数组的递推公式需要进行一定的变化,其他和上面的相同。

第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp**[i - 1]**[1]

第i天卖出股票,所得现金就是按照今天股票价格卖出后所得现金即:prices[i] + dp**[i - 1]**[0]

dp[i][0] = fmax(dp[i - 1][0], dp[i - 1][1] - prices[i]); 
dp[i][1] = fmax(dp[i - 1][0] + prices[i], dp[i - 1][1]); 

其他就是相同的

int maxProfit(int* prices, int pricesSize) {
    int dp[pricesSize][2];
    dp[0][0] = -prices[0];
    dp[0][1] = 0;
    for (int i = 1; i < pricesSize; i++) {
        dp[i][0] = fmax(dp[i - 1][0], dp[i - 1][1] - prices[i]);
        dp[i][1] = fmax(dp[i - 1][0] + prices[i], dp[i - 1][1]);
    }
    return fmax(dp[pricesSize -1][0], dp[pricesSize - 1][1]);
}

本题也有贪心解法:将利润拆分成每一天的利润只要是正利润就相加

int maxProfit(int* prices, int pricesSize){
    int result = 0;
    int i;
    for(i = 1; i < pricesSize; ++i) {
        if(prices[i] > prices[i-1])
            result+= prices[i]-prices[i-1];
    }
    return result;
}

123. 买卖股票的最佳时机 III - 力扣(LeetCode)

这题目固定了售卖的次数,所以我们需要重新分析这道题目

  • 确定dp数组和其下标含义

    • 没有操作 (其实我们也可以不设置这个状态)
    • 第一次持有股票
    • 第一次不持有股票
    • 第二次持有股票
    • 第二次不持有股票
  • 分析递推公式

    • 我们发现其实递推公式还是和上一道一样,只不过我们需要考虑的是第几次操作。

      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]);
      
  • 初始化

    • dp[0][0]和dp[0][2]初始化为0
    • dp[1][1]和dp[0][3]初始化为-price[0];
  • 遍历顺序

    • 遍历顺序 依旧是从前到后。
  • 举例递推

代码如下:

int maxProfit(int* prices, int pricesSize) {
    int dp[pricesSize][5];
    dp[0][0] = 0;
    dp[0][2] = 0;
    dp[0][1] = -prices[0];
    dp[0][3] = -prices[0];
    dp[0][4] = 0;
    for(int i = 1; i < pricesSize; i++) {
        dp[i][0] = dp[i - 1][0];
        dp[i][1] = fmax(dp[i - 1][1], dp[i - 1][0] - prices[i]); //和第二题一样枚举情况
        dp[i][2] = fmax(dp[i - 1][2], dp[i - 1][1] + prices[i]);
        dp[i][3] = fmax(dp[i - 1][3], dp[i - 1][2] - prices[i]);
        dp[i][4] = fmax(dp[i - 1][4], dp[i - 1][3] + prices[i]);
    }
    return dp[pricesSize - 1][4];
}

笔者能力有限,理解浅薄,若有错误还请指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值