面试必刷算法TOP101之买卖股票问题 TOP16

一个思路解决下边买卖股票的问题
首先先分析下边的问题
121. 买卖股票的最佳时机 I 限定交易次数 k=1
122. 买卖股票的最佳时机 II 交易次数无限制 k = N
123. 买卖股票的最佳时机 III 限定交易次数 k=2
124. 买卖股票的最佳时机 IV 限定交易次数 最多次数为 k k还是有限制的
这些问题都是买卖股票的最佳时机,都是在通过买卖股票的来获取最大差值大,但是最大区别就是买卖股票的次数都是不一样的,所以将这些问题看作是一个问题,只不过是对于不同问题交易次数是不同的,因为是动态规划问题还是使用PD的解题步骤来解决问题:
(1)创建dp数组明确下标的含义
创建一个三维数组dp[i][k][j]其含义是在第i天剩余叫次数还有k次,对于j来说不是0就是1,0代表没有股票,1代表持有股票,具体含义如下:

dp[i][k][0] 第i天 还可以交易k次 手中没有股票
dp[i][k][1] 第i天 还可以交易k次 手中有股票

最后的结果应该是dp[i][k][0]手中应该没有持有股票,因为最后一天持有股票的化没有卖出其收益肯定不是最高的

(2)递推公式
因为定义dp数组时定义第i天持有股票和没有持有股票所以分为两种情况

第i天没有持有股票,可以分为两种情况
在这里插入图片描述

递推公式为:dp[i][k][0] = max(dp[i - 1][k][0], dp[i - 1][k][1] + cost[i])
// 今天没有持有股票,分为两种情况
// 1. dp[i - 1][k][0],昨天没有持有,今天不操作。
// 2. dp[i - 1][k][1] + prices[i] 昨天持有,今天卖出,今天手中就没有股票了。

第i天持有股票,可以分为两种情况
在这里插入图片描述
递推公式为:p[i][k][1] = max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - cost[i]
// 今天持有股票,分为两种情况:
// 1.dp[i - 1][k][1] 昨天持有,今天不操作
// 2.dp[i - 1][k - 1][0] - prices[i] 昨天没有持有,今天买入。

最大利益就是将持股与不持股情况比较去一个最大值

(3)初始化‘
每个问题的情况不一样初始化也是不样的
(4)遍历顺序
因为都是前边买入后边卖出所以遍历方式自然就是从前往后

股票问题以之 买卖股票的最佳时机Ⅰ

题目来源:Leetcode

1、问题描述

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。

2、转移方程式

前边已经总结出来大的思路但是每一个问题,还有一些是不同的针对这个问题还是要具体分析
转移方程
//第i天不持有 由 第i-1天不持有然后不操作 和 第i-1天持有然后卖出 两种情况的最大值转移过来
dp[i][1][0] = max(dp[i - 1][1][0], dp[i - 1][1][1] + cost[i])
//第i天持有 由 第i-1天持有然后不操作 和 第i-1天不持有然后买入 两种情况的最大值转移过来
dp[i][1][1] = Math.max(dp[i - 1][1][1], dp[i - 1][0][0] - prices[i])
= max(dp[i - 1][1][1], -cost[i]) // k=0时 没有交易次数,dp[i - 1][0][0] = 0

dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - cost[i]
dp[i][[1] = max(dp[i - 1][1], cost[i]) k=0时 没有交易次数,dp[i - 1][0][0] = 0
简化为一个二为数组但是结果还是不影响

3.代买实现

``
class Solution {
public:

int maxProfit(vector<int>& prices) {
    int n = prices.size();
    int dp[n][2];
    dp[0][0] = 0;
    dp[0][1] = -prices[0];//因为第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], - prices[i]);
    }
    return dp[n - 1][0];
}

};



前边代码dp[i]之与dp[i-1]有关可以将dp数组降维到一维数组

```kotlin
int maxProfit(vector<int>& prices) {
        int n = prices.size();
        int dp[2];
        dp[0] = 0;
        dp[1] = -prices[0];//因为第0天买入的话就持股就是-prices[0]
        for (int i = 1; i < n; ++i) {
            dp[0] = max(dp[0], dp[1] + prices[i]);
            dp[1] = max(dp[1], - prices[i]);
        }
        return dp[0];
    }

股票问题以之 买卖股票的最佳时机Ⅱ

题目来源:Leetcode

1、问题描述

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。

2、转移方程式

//第i天不持有 由 第i-1天不持有然后不操作 和 第i-1天持有然后卖出 两种情况的最大值转移过来
dp[i][1][0] = max(dp[i - 1][1][0], dp[i - 1][1][1] + cost[i])
//第i天持有 由 第i-1天持有然后不操作 和 第i-1天不持有然后买入 两种情况的最大值转移过来
dp[i][1][1] = Math.max(dp[i - 1][1][1], dp[i - 1][0][0] - prices[i])

dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - cost[i]
dp[i][[1] = max(dp[i - 1][1], dp[i - 1][0][0] -cost[i])

3代码实现

 
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        int dp[2];
        dp[0] = 0;
        dp[1] = -prices[0];//因为第0天买入的话就持股就是-prices[0]
        for (int i = 1; i < n; ++i) {
            dp[0] = max(dp[0], dp[1] + prices[i]);
            dp[1] = max(dp[1], - prices[i]);
        }
        return dp[0];
    }

买卖股票的最佳时机Ⅲ

题目来源:Leetcode

1、问题描述

给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

2、转移方程式

//第i天不持有 由 第i-1天不持有然后不操作 和 第i-1天持有然后卖出 两种情况的最大值转移过来
dp[i][1][0] = max(dp[i - 1][1][0], dp[i - 1][1][1] + cost[i])
//第i天持有 由 第i-1天持有然后不操作 和 第i-1天不持有然后买入 两种情况的最大值转移过来
dp[i][1][1] = Math.max(dp[i - 1][1][1], dp[i - 1][0][0] - prices[i])

K对结果有影响不能舍弃
对其循环

for (let i = 0; i < n; i++) {
  for (let k = maxK; k >= 1; k--) {
    dp[i][k][0] = Mmax(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i]);
    dp[i][k][1] = max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i]);
  }
}

先写出i为2和1时的结果
i为2时
dp[i][1][0] = max(dp[i - 1][1][0], dp[i - 1][1][1] + cost[i])
dp[i][1][1] = Math.max(dp[i - 1][1][1], dp[i - 1][0][0] - prices[i])
还是这样
.

i为1时
就成了买卖股票的最佳时机的情况
因为当k==0时没有交易次数,dp[i - 1][0][0] = 0所以就会出现如下情况;
dp[i][1][1] = max(dp[i - 1][1][1], dp[i - 1][0][0] - prices[i])
= max(dp[i - 1][1][1], -cost[i])
dp[i][1][0] = max(dp[i - 1][1][0], dp[i - 1][1][1] + cost[i])

去掉中间这一维
dp[i][1][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i])
= max(dp[i - 1][1], -cost[i])
dp[i][1][0] = max(dp[i - 1][0], dp[i - 1][1] + cost[i])

3代买实现

//和前面一样 我们直接降维
 int maxProfit(vector<int>& prices) {
       int buy_1 = -prices[0], sell_1 = 0;
        int buy_2 = -prices[0], sell_2 = 0;
        int n = prices.size();
        for (int i = 1; i < n; i++) {
            sell_2 = max(sell_2, buy_2 + prices[i]);
            buy_2 = max(buy_2, sell_1 - prices[i]);
            sell_1 = max(sell_1, buy_1 + prices[i]);
            buy_1 = max(buy_1, -prices[i]);
        }
          return sell_2;
    }


  • 33
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 32
    评论
评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

自首的小偷

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

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

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

打赏作者

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

抵扣说明:

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

余额充值