4.16 股票买卖 小偷问题

This commit is contained in:
zhangsan 2025-04-16 11:21:54 +08:00
parent 7b5c5e4c08
commit c44787299a
5 changed files with 187 additions and 8 deletions

View File

@ -0,0 +1,55 @@
package dynamic_programming;
/**
* 题目 121. 买卖股票的最佳时机 (maxProfit)
* 描述给定一个数组 prices 它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格
* 你只能选择 某一天 买入这只股票并选择在 未来的某一个不同的日子 卖出该股票设计一个算法来计算你所能获取的最大利润
* 返回你可以从这笔交易中获取的最大利润如果你不能获取任何利润返回 0
* 示例 1
输入[7,1,5,3,6,4]
输出5
解释在第 2 股票价格 = 1的时候买入在第 5 股票价格 = 6的时候卖出最大利润 = 6-1 = 5
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格同时你不能在买入前卖出股票
* 链接https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/
*/
//需要琢磨
public class MaxProfit {
public int maxProfit(int[] prices) {
int n = prices.length;
if (n < 2) return 0;
// dp[i][0] i 天持有股票的最大收益
// dp[i][1] i 天不持有股票的最大收益
int[][] dp = new int[n][2];
// 边界 0
dp[0][0] = -prices[0];
dp[0][1] = 0;
for (int i = 1; i < n; i++) {
// 今天持有要么延续昨天持有要么今天买入只能买一次
dp[i][0] = Math.max(dp[i - 1][0], -prices[i]);
// 今天不持有要么延续昨天不持有要么今天卖出
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
}
// 最终答案最后一天不持有时的最大收益
return dp[n - 1][1];
}
public int maxProfit1(int[] prices) {
int n = prices.length;
if (n < 2) return 0;
int hold = -prices[0]; // 对应 dp[0][0]
int notHold = 0; // 对应 dp[0][1]
for (int i = 1; i < n; i++) {
// 注意更新顺序先算不持有再算持有也可以但要保证用到的是前一天的状态
hold = Math.max(hold, -prices[i]);
notHold = Math.max(notHold, hold + prices[i]);
}
return notHold;
}
}

View File

@ -0,0 +1,40 @@
package dynamic_programming;
/**
* 题目 122. 买卖股票的最佳时机 II (maxProfit)
* 描述给你一个整数数组 prices 其中 prices[i] 表示某支股票第 i 天的价格
* 在每一天你可以决定是否购买和/或出售股票你在任何时候 最多 只能持有 一股 股票你也可以先购买然后在 同一天 出售
* 返回 你能获得的 最大 利润
* <p>
* 示例 1
* 输入prices = [7,1,5,3,6,4]
* 输出7
* 解释在第 2 股票价格 = 1的时候买入在第 3 股票价格 = 5的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4
* 随后在第 4 股票价格 = 3的时候买入在第 5 股票价格 = 6的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3
* 最大总利润为 4 + 3 = 7
* <p>
* 链接https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/
*/
//不会dp做法
public class MaxProfit2 {
// 由于允许多次交易今天买入的收益要在昨天不持有的基础上减去今天的价格今天卖出的收益要在昨天持有的基础上加上今天的价格
// dp[i][0]第i天持有股票时的最大收益
//dp[i][1]第i天不持有股票时的最大收益
public int maxProfit(int[] prices) {
int n = prices.length;
if (n < 2) return 0;
int[][] dp = new int[n][2];
// 0
dp[0][0] = -prices[0];
dp[0][1] = 0;
for (int i = 1; i < n; 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[n - 1][1];
}
}

View File

@ -0,0 +1,82 @@
package dynamic_programming;
import tree.TreeNode;
import java.util.*;
/**
* 题目 337. 打家劫舍 III (rob)
* 描述小偷又发现了一个新的可行窃的地区这个地区只有一个入口我们称之为 root
* 除了 root 之外每栋房子有且只有一个房子与之相连一番侦察之后聪明的小偷意识到这个地方的所有房屋的排列类似于一棵二叉树 如果 两个直接相连的房子在同一天晚上被打劫 房屋将自动报警
* 给定二叉树的 root 返回 在不触动警报的情况下 小偷能够盗取的最高金额
*
示例 2
输入: root = [3,2,3,null,3,null,1]
输出: 7
解释: 小偷一晚能够盗取的最高金额 3 + 3 + 1 = 7
* 链接https://leetcode.cn/problems/house-robber-iii/
*/
public class Rob3 {
// 1.递归去偷超时
public int rob(TreeNode root) {
if (root == null)
return 0;
//偷父节点
int money = root.val;
if (root.left != null) {
money += rob(root.left.left) + rob(root.left.right);
}
if (root.right != null) {
money += rob(root.right.left) + rob(root.right.right);
}
return Math.max(money, rob(root.left) + rob(root.right));
}
// 2.递归去偷记录状态
public int rob1(TreeNode root) {
Map<TreeNode, Integer> memo = new HashMap<>();
return robAction(root, memo);
}
int robAction(TreeNode root, Map<TreeNode, Integer> memo) {
if (root == null)
return 0;
if (memo.containsKey(root))
return memo.get(root);
int money = root.val;
if (root.left != null) {
money += robAction(root.left.left, memo) + robAction(root.left.right, memo);
}
if (root.right != null) {
money += robAction(root.right.left, memo) + robAction(root.right.right, memo);
}
int res = Math.max(money, robAction(root.left, memo) + robAction(root.right, memo));
memo.put(root, res);
return res;
}
// 3.状态标记递归
// 执行用时0 ms , 在所有 Java 提交中击败了 100% 的用户
// 不偷Max(左孩子不偷左孩子偷) + Max(右孩子不偷右孩子偷)
// root[0] = Math.max(rob(root.left)[0], rob(root.left)[1]) +
// Math.max(rob(root.right)[0], rob(root.right)[1])
// 左孩子不偷+ 右孩子不偷 + 当前节点偷
// root[1] = rob(root.left)[0] + rob(root.right)[0] + root.val;
public int rob3(TreeNode root) {
int[] res = robAction1(root);
return Math.max(res[0], res[1]);
}
int[] robAction1(TreeNode root) {
int res[] = new int[2];
if (root == null)
return res;
int[] left = robAction1(root.left);
int[] right = robAction1(root.right);
res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
res[1] = root.val + left[0] + right[0];
return res;
}
}

View File

@ -14,8 +14,9 @@ package greedy;
* 链接https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/
*/
//考虑复杂了
public class MaxProfit2 {
//考虑复杂了
public int maxProfit1(int[] prices) {
int prediff=0,curdiff=0,maxprofit=0,buyprice=0;
boolean flag=false;

View File

@ -1,17 +1,18 @@
package tree;
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {
}
TreeNode(int val) {
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode() {}
public TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
public TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}