兰州正规seo整站优化工具,网络管理网站策划书,下载手机版app,东莞网络推广哪家公司奿引入
股票问题是一类动态问题#xff0c;我们需要对其状态进行判定分析来得出答案
但其实#xff0c;我们只需要抓住两个点#xff0c;持有和不持有#xff0c;在这两种状态下分析问题会简单清晰许多
下面将会对各个问题进行分析讲解#xff0c;来解释什么是持有和不持…引入
股票问题是一类动态问题我们需要对其状态进行判定分析来得出答案
但其实我们只需要抓住两个点持有和不持有在这两种状态下分析问题会简单清晰许多
下面将会对各个问题进行分析讲解来解释什么是持有和不持有状态并在分析后得到题目的解答买卖股票的最佳时机 1、买卖股票的最佳时机
给定一个数组 prices 它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润返回 0 。
示例 1 输入[7,1,5,3,6,4] 输出5 解释在第 2 天股票价格 1的时候买入在第 5 天股票价格 6的时候卖出最大利润 6-1 5 。注意利润不能是 7-1 6, 因为卖出价格需要大于买入价格同时你不能在买入前卖出股票。
示例 2 输入prices [7,6,4,3,1] 输出0 解释在这种情况下, 没有交易完成, 所以最大利润为 0。
分析
我们了解到这道题只能够购买和卖出一次那么
持有的状态只有两种情况1.之前就持有 2.今天刚买入
不持有也有两种情况1.昨天就不持有 2.今天刚出售
1.dp空间
通过以上的分析我们可以知道解决这个问题我们需要了解
1.今天的价格 2.昨天的状态
所以我们需要两对空间保存两对持有与不持有状态
即一个2*2大小的数组
vectorvectorint dp(2, vectorint(2)); 2.初始状态
其中dp[i][0] 代表第i天的持有状态下的资金数 dp[i][1] 代表第i天的不持有状态下的资金数
由此我们也可以知道第一天的持有状态只能是进行买入 即 -prices[0] 不持有状态只能是0
所以初始状态我们也有了
dp[0][0] -prices[0];
dp[0][1] 0; 3.递推公式
由刚开始的分析其实我们已经知道了递推公式现在只需要进行代码实现即可 先使用伪代码描述 当天持有股票的最大金额 max昨天就持有时的资金数今天刚买入后所拥有的资金 当天不持有股票的最大金额 max昨天就不持有时的资金数今天刚卖出后所拥有的资金 代码实现
其中的取模运算是为了获得之前的状态而不用进行数据移动
//因为只进行一次买入卖出所以当前买入一定是 0 - prices[i]
dp[i % 2][0] max(dp[(i - 1) % 2][0], -prices[i]);
dp[i % 2][1] max(dp[(i - 1) % 2][1], prices[i] dp[(i - 1) % 2][0]); 4.题解代码
class Solution {
public:int maxProfit(vectorint prices) {int len prices.size();vectorvectorint dp(2, vectorint(2)); dp[0][0] -prices[0];dp[0][1] 0;for (int i 1; i len; i) {dp[i % 2][0] max(dp[(i - 1) % 2][0], -prices[i]);dp[i % 2][1] max(dp[(i - 1) % 2][1], prices[i] dp[(i - 1) % 2][0]);}return dp[(len - 1) % 2][1];}
}; 2、买卖股票的最佳时机 II
给定一个数组它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易多次买卖一支股票。
注意你不能同时参与多笔交易你必须在再次购买前出售掉之前的股票。
示例 1: 输入: [7,1,5,3,6,4] 输出: 7 解释: 在第 2 天股票价格 1的时候买入在第 3 天股票价格 5的时候卖出, 这笔交易所能获得利润 5-1 4。随后在第 4 天股票价格 3的时候买入在第 5 天股票价格 6的时候卖出, 这笔交易所能获得利润 6-3 3 。
示例 2: 输入: [1,2,3,4,5] 输出: 4 解释: 在第 1 天股票价格 1的时候买入在第 5 天 股票价格 5的时候卖出, 这笔交易所能获得利润 5-1 4 。注意你不能在第 1 天和第 2 天接连购买股票之后再将它们卖出。因为这样属于同时参与了多笔交易你必须在再次购买前出售掉之前的股票。
示例 3: 输入: [7,6,4,3,1] 输出: 0 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
提示
1 prices.length 3 * 10 ^ 40 prices[i] 10 ^ 4
分析
这道题与上一道题的最大差别就是可进行多次买入卖出那么如上一道题相同先分析两种状态
持有的状态只有两种情况1.之前就持有 2.今天买入
不持有也有两种情况1.昨天就不持有 2.今天出售
1.dp空间
通过以上的分析我们可以知道解决这个问题我们需要了解
1.今天的价格 2.昨天的状态
所以我们需要两对空间保存两对持有与不持有状态
即一个2*2大小的数组
vectorvectorint dp(2, vectorint(2)); 2.初始状态
其中dp[i][0] 代表第i天的持有状态下的资金数 dp[i][1] 代表第i天的不持有状态下的资金数
由此我们也可以知道第一天的持有状态只能是进行买入 即 -prices[0] 不持有状态只能是0
所以初始状态与上一道题相同
dp[0][0] -prices[0];
dp[0][1] 0; 3.递推公式 使用伪代码描述 当天持有股票的最大金额 max昨天就持有时的资金数今天买入后所拥有的资金 当天不持有股票的最大金额 max昨天就不持有时的资金数今天刚卖出后所拥有的资金 代码实现
其中的取模运算是为了获得之前的状态而不用进行数据移动
注意因为需要进行多次买入卖出所以 持有股票状态中 今天买入后所拥有的资金 需要由之前的状态转换而来这是与前一道题不同的地方
//注意这里的今天买入状态是由昨天未持有状态推导而来
dp[i % 2][0] max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1] - prices[i]);
dp[i % 2][1] max(dp[(i - 1) % 2][1], prices[i] dp[(i - 1) % 2][0]); 4.题解代码
class Solution {
public:int maxProfit(vectorint prices) {int len prices.size();vectorvectorint dp(2, vectorint(2));dp[0][0] - prices[0];dp[0][1] 0;for (int i 1; i len; i) {dp[i % 2][0] max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1] - prices[i]);dp[i % 2][1] max(dp[(i - 1) % 2][1], prices[i] dp[(i - 1) % 2][0]);}return dp[(len - 1) % 2][1];}
}; 3、买卖股票的最佳时机 III
给定一个数组它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意你不能同时参与多笔交易你必须在再次购买前出售掉之前的股票。
示例 1: 输入prices [3,3,5,0,0,3,1,4] 输出6 解释在第 4 天股票价格 0的时候买入在第 6 天股票价格 3的时候卖出这笔交易所能获得利润 3-0 3 。随后在第 7 天股票价格 1的时候买入在第 8 天 股票价格 4的时候卖出这笔交易所能获得利润 4-1 3。
示例 2 输入prices [1,2,3,4,5] 输出4 解释在第 1 天股票价格 1的时候买入在第 5 天 股票价格 5的时候卖出, 这笔交易所能获得利润 5-1 4。注意你不能在第 1 天和第 2 天接连购买股票之后再将它们卖出。因为这样属于同时参与了多笔交易你必须在再次购买前出售掉之前的股票。
示例 3 输入prices [7,6,4,3,1] 输出0 解释在这个情况下, 没有交易完成, 所以最大利润为0。
示例 4 输入prices [1] 输出0
提示
1 prices.length 10^50 prices[i] 10^5
分析
这道题与前题的差别在于只能进行两笔交易即两次买入卖出过程那么如上一道题相同先分析两笔交易各自的状态
第一笔
持有的状态只有两种情况1.之前就持有 2.今天刚买入
不持有也有两种情况1.昨天就不持有 2.今天刚出售
但是情况不同的是第二笔的交易需要根据第一笔交易的基础上进行
所以第二笔
持有的状态只有两种情况1.之前就持有 2.今天刚买入但需要加上前一笔交易完成的状态
不持有也有两种情况1.昨天就不持有 2.今天刚出售 1.dp空间
通过以上的分析我们可以知道解决这个问题我们需要了解
1.第一笔交易的持有与不持有状态 2.第一笔交易的持有与不持有状态
所以我们需要两对空间保存两笔交易的状态
即一个2*2大小的数组
vectorvectorint dp(2, vectorint(2, 0)); 2.初始状态
其中dp[i][0] 代表第i天的持有状态下的资金数 dp[i][1] 代表第i天的不持有状态下的资金数
由此我们也可以知道第一天第一笔的持有状态只能是进行买入 即 -prices[0] 不持有状态只能是0
又因为第二笔的状态根据第一笔的状态转换
所以第二笔的持有状态是第一笔的不持有状态-当前价格 即 0-prices[0] 不持有状态只能是0
所以初始状态如下
dp[0][0] -prices[0];
dp[1][0] -prices[0]; 3.递推公式 使用伪代码描述 第一笔交易持有股票的最大金额 max昨天就持有时的资金数今天买入后所拥有的资金 第一笔交易不持有股票的最大金额 max昨天就不持有时的资金数今天刚卖出后所拥有的资金 第二笔交易持有股票的最大金额 max昨天就持有时的资金数今天买入后所拥有的资金 第二笔交易不持有股票的最大金额 max昨天就不持有时的资金数今天刚卖出后所拥有的资金 代码实现
至于为什么不保存第一笔之前的状态了大致可以理解为两天合起来才是需要的完整的交易即第一笔就保存了第二笔之前的数据第一笔直接交易即可
dp[0][0] std::max(dp[0][0], 0 - prices[i]);
dp[0][1] std::max(dp[0][1], prices[i] dp[0][0]);
dp[1][0] std::max(dp[1][0], dp[0][1] - prices[i]);
dp[1][1] std::max(dp[1][1], prices[i] dp[1][0]); 4.题解代码
class Solution {
public:int maxProfit(vectorint prices) {int n prices.size();vectorvectorint dp(2, vectorint(2, 0));dp[0][0] -prices[0];dp[1][0] -prices[0];for (int i 1; i n; i) {dp[0][0] std::max(dp[0][0], 0 - prices[i]);dp[0][1] std::max(dp[0][1], prices[i] dp[0][0]);dp[1][0] std::max(dp[1][0], dp[0][1] - prices[i]);dp[1][1] std::max(dp[1][1], prices[i] dp[1][0]);}return dp[1][1];}
}; 4、买卖股票的最佳时机 IV
给定一个整数数组 prices 它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意你不能同时参与多笔交易你必须在再次购买前出售掉之前的股票。
示例 1 输入k 2, prices [2,4,1] 输出2 解释在第 1 天 (股票价格 2) 的时候买入在第 2 天 (股票价格 4) 的时候卖出这笔交易所能获得利润 4-2 2。
示例 2 输入k 2, prices [3,2,6,5,0,3] 输出7 解释在第 2 天 (股票价格 2) 的时候买入在第 3 天 (股票价格 6) 的时候卖出, 这笔交易所能获得利润 6-2 4。随后在第 5 天 (股票价格 0) 的时候买入在第 6 天 (股票价格 3) 的时候卖出, 这笔交易所能获得利润 3-0 3 。
提示
0 k 1000 prices.length 10000 prices[i] 1000
分析
其实这道题与前一道题是相同的题目只是将交易次数修改为任意次数
只需要与上道题进行相同的模式即可
这里就直接摆出代码
但需要注意的是第一笔交易买入时肯定是0 - prices[i]的价值所以在此处使用多开一层数组来保持动态的首次为0的概念即代码中的
dp[j - 1][1] - prices[i]
class Solution {
public:int maxProfit(int k, vectorint prices) {int n prices.size();vectorvectorint dp(k 1, vectorint(2, 0));for (int i 1; i k; i) {dp[i][0] -prices[0];}for (int i 1; i n; i) {for (int j 1; j k; j) {dp[j][0] std::max(dp[j][0], dp[j - 1][1] - prices[i]);dp[j][1] std::max(dp[j][1], prices[i] dp[j][0]);}}return dp[k][1];}
}; 5、最佳买卖股票时机含冷冻期
给定一个整数数组其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下你可以尽可能地完成更多的交易多次买卖一支股票:
你不能同时参与多笔交易你必须在再次购买前出售掉之前的股票。卖出股票后你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
输入: [1,2,3,0,2]输出: 3解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
分析
这道题与前面的题就不一样了因为这道题多出了一种状态即冰冻期的状态
让我们对三种状态进行分析
持有1.前一天就持有 2.今天刚持有
不持有1.前一天就不持有 2.今天是冷冻期
冷冻期今天卖出进入冷冻期
可能对这个分割会有疑虑为什么冷冻期的状态不算冷冻期当天而是算其交易完成的那天
因为我们一直都有在进行转换的判断
比如持有的状态是今天由不持有转向持有 不持有的状态是由持有转向不持有
所以冷冻期的概念是由非冷冻期转向冷冻期 2.初始状态
初始状态不涉及冷冻期所以初始状态没有变化 3.递推公式 使用伪代码描述 交易持有股票的最大金额 max昨天就持有时的资金数今天买入后所拥有的资金 交易不持有股票的最大金额 max昨天就不持有时的资金数今天是冷冻期的资金 冷冻期的最大金额 今天卖出后的资金 代码实现
dp[i][0] std::max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
dp[i][1] std::max(dp[i - 1][2], dp[i - 1][1]);
dp[i][2] dp[i - 1][0] prices[i]; 4.题解代码
注意交易结束的最大金额是由两个方面来决定不持有状态和冷冻期状态 class Solution {
public:int maxProfit(vectorint prices) {int n prices.size();vectorvectorint dp(n, vectorint(3, 0));dp[0][0] -prices[0];for (int i 1; i n; i) {dp[i][0] std::max(dp[i - 1][0], dp[i - 1][1] - prices[i]);dp[i][1] std::max(dp[i - 1][2], dp[i - 1][1]);dp[i][2] dp[i - 1][0] prices[i];}return std::max(dp[n - 1][1], dp[n - 1][2]);}
}; 6、买卖股票的最佳时机含手续费
给定一个整数数组 prices其中第 i 个元素代表了第 i 天的股票价格 非负整数 fee 代表了交易股票的手续费用。
你可以无限次地完成交易但是你每笔交易都需要付手续费。如果你已经购买了一个股票在卖出它之前你就不能再继续购买股票了。
返回获得利润的最大值。
注意这里的一笔交易指买入持有并卖出股票的整个过程每笔交易你只需要为支付一次手续费。
示例 1: 输入: prices [1, 3, 2, 8, 4, 9], fee 2 输出: 8
解释: 能够达到的最大利润: 在此处买入 prices[0] 1 在此处卖出 prices[3] 8 在此处买入 prices[4] 4 在此处卖出 prices[5] 9 总利润: ((8 - 1) - 2) ((9 - 4) - 2) 8.
注意:
0 prices.length 50000.0 prices[i] 50000.0 fee 50000.
分析
这个题就很简单了只是在第二题的基础上加了个交易费而已
就直接放出代码即可
此处数组的层数改为n但依旧是之前保存前一天的概念没有区别
class Solution {
public:int maxProfit(vectorint prices, int fee) {int n prices.size();vectorvectorint dp(n, vectorint(2, 0));dp[0][0] -prices[0];for (int i 1; i n; i) {dp[i][1] std::max(dp[i - 1][1], dp[i - 1][0] prices[i] - fee);dp[i][0] std::max(dp[i - 1][0], dp[i - 1][1] - prices[i]);}return dp[n - 1][1];}
};