[LeetCode] 122. 买卖gp的最佳时机 II
[LeetCode] 122. 买卖gp的最佳时机 II 文章解释
[LeetCode] 122. 买卖gp的最佳时机 II
自己看到题目的第一想法
hhh, 看了那么多遍,不懂也背下来了。 核心点在于,每天都尝试买卖一下,但是发现如果成本或者收益没有更优,就放弃操作。
看完代码随想录之后的想法
关键在于递推公式,如果单纯通过文字来理解递推公式的话,真的挺难接受的。但目前也慢慢接受了,数学推演部分也有一点点感受,总体就是如果当天买入股票后手上余额没有变多,说明股票价格上涨了。因为当前手上的余额表示的是在高点卖出股票后手上余额的值,余额没有变多说明股价在上涨,不能做买入操作。同理卖出也是一样,如果卖出后余额没有更多,说明股价在下跌,不需要继续卖出了。
class Solution {
public int maxProfit(int[] prices) {
// dp[i][0] 表示当天买入gp后,账户剩余的资金。
// dp[i][1] 表示当天卖出gp后,账户剩余的资金。
// 对于 dp[i][0]
// 如果当天买入gp后,比前一天买入gp后剩余资金更少,说明股价在上涨,因此要保持前一天买入gp的状态
// 如果当天买入gp后,比前一天买入gp后剩余资金更多,说明股价下跌了,因此要更新买入gp的状态
// 同理,对于 dp[i][1]
// 如果当天卖出gp后,比前一天卖出gp后剩余资金更少,说明股价在下跌,因此要保持前一天卖出gp的状态
// 如果当天卖出gp后,比前一天卖出gp后剩余资金更多,说明股价在上涨,因此要更新gp卖出的状态。
// gp的状态都有一个线性递进的状态,里面有很奇妙的数学关系~
// 整体的话只能记住这个递推公式了,因为目前看暂时是正确的。
int[][] dp = new int[prices.length][2];
// 递推公式:
// dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i])
// dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i])
// 初始化
dp[0][0] = -prices[0];
dp[0][1] = 0;
for (int i = 1; i < prices.length; i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
}
return dp[dp.length - 1][1];
}
}
// 一维数组版本
class Solution {
public int maxProfit(int[] prices) {
// dp[0] 表示当天买入gp后,账户剩余的资金。
// dp[1] 表示当天卖出gp后,账户剩余的资金。
// 对于 dp[0]
// 如果当天买入gp后,比前一天买入gp后剩余资金更少,说明股价在上涨,因此要保持前一天买入股票的状态
// 如果当天买入gp后,比前一天买入gp后剩余资金更多,说明股价下跌了,因此要更新买入股票的状态
// 同理,对于 dp[1]
// 如果当天卖出gp后,比前一天卖出gp后剩余资金更少,说明股价在下跌,因此要保持前一天卖出股票的状态
// 如果当天卖出gp后,比前一天卖出gp后剩余资金更多,说明股价在上涨,因此要更新gp卖出的状态。
// gp的状态都有一个线性递进的状态,里面有很奇妙的数学关系~
// 整体的话只能记住这个递推公式了,因为目前看暂时是正确的。
int[] dp = new int[2];
// 递推公式:
// dp[0] = Math.max(dp[0], dp[1] - prices[i])
// dp[1] = Math.max(dp[1], dp[0] + prices[i])
// 初始化
dp[0] = -prices[0];
dp[1] = 0;
for (int i = 1; i < prices.length; i++) {
dp[0] = Math.max(dp[0], dp[1] - prices[i]);
dp[1] = Math.max(dp[1], dp[0] + prices[i]);
}
return dp[1];
}
}
// 贪心版本
class Solution {
public int maxProfit(int[] prices) {
int sum = 0;
for (int i = 1; i < prices.length; i++) {
if (prices[i] > prices[i - 1]) {
sum += (prices[i] - prices[i - 1]);
}
}
return sum;
}
}
自己实现过程中遇到哪些困难
无,看过太多遍了。。。
[LeetCode] 123. 买卖gp的最佳时机 III
[LeetCode] 123. 买卖gp的最佳时机 III 文章解释[LeetCode] 123. 买卖gp的最佳时机 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
[LeetCode] 123. 买卖gp的最佳时机 III
自己看到题目的第一想法
不要为难我啊胖虎。。。
看完代码随想录之后的想法
将原来的每天买和卖的操作(dp[2]),升级成了通过五个状态(dp[5])来模拟每天买卖后账户的余额。
重要的是递推公式,还是挺有规律的
dp[i][0] = dp[i - 1][0];// 其实就是等于0
dp[i][1] = dp[i - 1][0] - prices[i];// 等于 -prices[i]
dp[i][2] = dp[i - 1][1] + prices[i];
dp[i][3] = dp[i - 1][2] - prices[i];
dp[i][4] = dp[i - 1][3] + prices[i];
class Solution {
public int maxProfit(int[] prices) {
// dp[0] 当前无操作账户上的现金
// dp[1] 第一次买入后账户上的现金
// dp[2] 第一次卖出后账户上的现金
// dp[3] 第二次买入后账户上的现金
// dp[4] 第二次卖出后账户上的现金
int[][] dp = new int[prices.length][5];
// 递推公式
// dp[i][0] = dp[i - 1][0]
// dp[i][1] = max(dp[i][1], dp[i][0] - prices[i])
// dp[i][2] = max(dp[i][2], dp[i][1] + prices[i])
// dp[i][3] = max(dp[i][3], dp[i][2] - prices[i])
// dp[i][4] = max(dp[i][4], dp[i][3] + prices[i])
// 初始化:
dp[0][1] = dp[0][3] = -prices[0];
for (int i = 1; i < prices.length; i++) {
dp[i][0] = dp[i - 1][0];
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
}
return dp[dp.length - 1][4];
}
}
// 一维数组版
class Solution {
public int maxProfit(int[] prices) {
int[] dp = new int[5];
// 初始化:
dp[1] = dp[3] = -prices[0];
for (int i = 1; i < prices.length; i++) {
dp[1] = Math.max(dp[1], dp[0] - prices[i]);
dp[2] = Math.max(dp[2], dp[1] + prices[i]);
dp[3] = Math.max(dp[3], dp[2] - prices[i]);
dp[4] = Math.max(dp[4], dp[3] + prices[i]);
}
return dp[4];
}
}
自己实现过程中遇到哪些困难
无,知道通关公式后就简单了。
[LeetCode] 188. 买卖gp的最佳时机 IV
[LeetCode] 188. 买卖gp的最佳时机 IV 文章解释[LeetCode] 188. 买卖gp的最佳时机 IV 视频解释
题目:
给你一个整数数组
prices
和一个整数k
,其中prices[i]
是某支给定的股票在第i
天的价格。设计一个算法来计算你所能获取的最大利润。你最多可以完成
k
笔交易。也就是说,你最多可以买k
次,卖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 。提示:
1 <= k <= 100
1 <= prices.length <= 1000
0 <= prices[i] <= 1000
[LeetCode] 188. 买卖gp的最佳时机 IV
自己看到题目的第一想法
加速学习中,直接看的题解~ (主要是感觉挺复杂的)
看完代码随想录之后的想法
dp 数组膨胀了!重点是每天的递推公式。
dp[i][2k]
=> dp[i][奇数] = dp[i - 1][奇数 - 1] - prices[i]
=> dp[i][偶数] = dp[i - 1][偶数 - 1] + prices[i]
class Solution {
public int maxProfit(int k, int[] prices) {
int[][] dp = new int[prices.length][2 * k + 1];
// 初始化
for (int i = 1; i < 2 * k; i+=2) {
dp[0][i] = -prices[0];
}
for (int i = 1; i < dp.length; i++) {
dp[i][0] = dp[i - 1][0];
for (int j = 1; j <= 2 * k; j++) {
if (j%2 == 0) {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] + prices[i]);
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] - prices[i]);
}
}
}
return dp[dp.length - 1][2 *k];
}
}
class Solution {
public int maxProfit(int k, int[] prices) {
int[] dp = new int[2 * k + 1];
// 初始化
for (int i = 1; i < 2 * k; i+=2) {
dp[i] = -prices[0];
}
for (int i = 1; i < prices.length; i++) {
dp[0] = dp[0];
for (int j = 1; j <= 2 * k; j++) {
if (j%2 == 0) {
dp[j] = Math.max(dp[j], dp[j - 1] + prices[i]);
} else {
dp[j] = Math.max(dp[j], dp[j - 1] - prices[i]);
}
}
}
return dp[2 *k];
}
}
自己实现过程中遇到哪些困难
无
[LeetCode] 309. 买卖gp的最佳时机含冷冻期
[LeetCode] 309. 买卖gp的最佳时机含冷冻期 文章解释[LeetCode] 309. 买卖gp的最佳时机含冷冻期 视频解释
题目:
给定一个整数数组
prices
,其中第prices[i]
表示第i
天的股票价格 。设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
- 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: prices = [1,2,3,0,2] 输出: 3 解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]示例 2:
输入: prices = [1] 输出: 0提示:
1 <= prices.length <= 5000
0 <= prices[i] <= 1000
[LeetCode] 309. 买卖gp的最佳时机含冷冻期
自己看到题目的第一想法
(当前阶段:这是正常人想的明白的吗?)
看完代码随想录之后的想法
主要还是递推公式, 添加了四个状态: 0 买入状态 1 卖出状态(不包含刚卖出) 2 今天卖出 3 冷冻状态(前一天卖出的话,今天是冷冻状态)
买入状态: dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][1], dp[i - 1][3]) - prices[i]) // 卖出后有冷冻期,因此 2 状态不能买
卖出状态: dp[i][1] = max(dp[i - 1][1], dp[i - 1][3])
今天卖出: dp[i][2] = dp[i - 1][0] + prices[i]
冷冻状态: dp[i][3] = dp[i - 1][2]
class Solution {
public int maxProfit(int[] prices) {
// 神!!!冷冻期!!! 咱就说这一题就是背答案了。。。这解题思路不好想。
// 不看解释根本想不到这种状态推导公式
// 动态规划真的是越整越猛,越整越蒙
// dp[i][0] 买入与保持买入gp的状态
// dp[i][1] 保持卖出gp的状态
// dp[i][2] 今天卖出, 只有这个状态才能推导出冷冻期
// dp[i][3] 冷冻期
int[][] dp = new int[prices.length][4];
// 递推公式:
// dp[i][0] = Math.max(dp[i - 1][0], Math.max(dp[i - 1][1], dp[i - 1][3]) - prices[i]) // 买入与保持买入股票的状态
// dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][3]) // 保持卖出gp的状态
// dp[i][2] = dp[i - 1][0] + prices[i] // 今天卖出, 只有这个状态才能推导出冷冻期
// dp[i][3] = dp[i - 1][2] // 冷冻期
// 初始化
dp[0][0] = -prices[0];// 感觉初始化很容想错
for (int i = 1; i < dp.length; i++) {
dp[i][0] = Math.max(dp[i - 1][0], Math.max(dp[i - 1][1], dp[i - 1][3]) - prices[i]); // 卖出后有冷冻期,因此 2 状态不能买
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][3]);
dp[i][2] = dp[i - 1][0] + prices[i];
dp[i][3] = dp[i - 1][2];
}
return Math.max(dp[dp.length - 1][1], Math.max(dp[dp.length - 1][2], dp[dp.length - 1][3]));
}
}
一维数组版本有点问题,不想深究了。
自己实现过程中遇到哪些困难
无。