7.16 股票买卖

This commit is contained in:
zhangsan 2025-07-16 20:50:07 +08:00
parent 8c8f0d0b20
commit dbd0be69e8
7 changed files with 141 additions and 25 deletions

View File

@ -14,6 +14,7 @@ package dynamic_programming;
* 链接https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/
*/
//需要琢磨
//二刷会做
public class MaxProfit {
public int maxProfit(int[] prices) {
int n = prices.length;

View File

@ -5,17 +5,18 @@ package dynamic_programming;
* 描述给你一个整数数组 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天持有股票时的最大收益

View File

@ -16,6 +16,7 @@ package dynamic_programming;
* 链接https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/
*/
//不会
//二刷不会
public class MaxProfit3 {
/**
* 一天一共就有五个状态

View File

@ -14,8 +14,20 @@ package greedy;
* 链接https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/
*/
//第一次做没想出来每次都假设是今天卖出然后求今天之前的历史最低点
//第一次做没想出来每次都假设是今天卖出然后求今天之前的历史最低点
//二刷会做
public class MaxProfit {
public int maxProfit2(int[] prices) {
int maxprofit=0;
int minprice=prices[0];
for (int i = 1; i < prices.length; i++) {
if(prices[i]>minprice)maxprofit=Math.max(maxprofit,prices[i]-minprice);
else minprice=prices[i];
}
return maxprofit;
}
public int maxProfit(int prices[]) {
int minprice = Integer.MAX_VALUE;
int maxprofit = 0;

View File

@ -14,8 +14,15 @@ package greedy;
* 链接https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/
*/
//二刷会做
public class MaxProfit2 {
public int maxProfit2(int[] prices) {
int maxProfit=0;
for (int i = 1; i < prices.length; i++) {
maxProfit+=Math.max(prices[i]-prices[i-1],0);
}
return maxProfit;
}
//考虑复杂了
public int maxProfit1(int[] prices) {
int n = prices.length, profit = 0;

View File

@ -16,12 +16,13 @@ package greedy;
* 链接https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/
*/
//不会 困难题
//二刷不会
public class MaxProfit3 {
/**
* 举个小例子 prices = [1, 5, 2, 6] 4
*
* 左半段你能算出 left = [0, 4, 4, 5]
* left[i] 表示在第 0 天到第 i 天范围内最多做一笔交易能获得的最优利润
* 左半段left = [0, 4, 4, 5]
* right[i] 表示从第 i 天到最后一天这一段区间内最多做一笔交易能拿到的最大利润
* 右半段
* i=2价格 2为起点未来最高是 6利润 = 62 = 4
* i=1价格 5为起点未来最高同样 6利润 = 65 = 1
@ -33,33 +34,30 @@ public class MaxProfit3 {
*/
public int maxProfit(int[] prices) {
int n = prices.length;
if (n < 2) return 0; // (1)
if (n < 2) return 0;
// 1. left[i]: 0i 天内最多一笔交易的最优收益
int[] left = new int[n];
int minPrice = prices[0]; // (2)
int minPrice = prices[0];
for (int i = 1; i < n; i++) {
minPrice = Math.min(minPrice, prices[i]); // (3) 更新最低买入价
left[i] = Math.max(left[i - 1], // (4) 不做新交易今天卖出
prices[i] - minPrice);
minPrice = Math.min(minPrice, prices[i]);
left[i] = Math.max(left[i - 1], prices[i] - minPrice);
}
// 2. right[i]: in-1 天内最多一笔交易的最优收益
int[] right = new int[n + 1]; // (5) 右边界额外留 1用于 i=n-1 时访问
int maxPrice = prices[n - 1]; // (6)
for (int i = n - 1; i >= 0; i--) {
maxPrice = Math.max(maxPrice, prices[i]); // (7) 更新最高卖出价
right[i] = Math.max(right[i + 1], // (8) 不做新交易今天买入后再卖出
maxPrice - prices[i]);
int[] right = new int[n];
right[n - 1] = 0; // 只有最后一天无交易可能
int maxPrice = prices[n - 1];
for (int i = n - 2; i >= 0; i--) {
maxPrice = Math.max(maxPrice, prices[i]);
right[i] = Math.max(right[i + 1], maxPrice - prices[i]);
}
// 3. 枚举切分点第一笔结束在 i第二笔从 i+1 开始
int ans = 0;
for (int i = -1; i < n; i++) { // (9)
int leftProfit = (i >= 0) ? left[i] : 0; // (10)
int rightProfit = (i + 1 < n) ? right[i + 1] : 0; // (11)
ans = Math.max(ans, leftProfit + rightProfit); // (12)
// 3. 合并两段写法 B更简洁
int ans = right[0]; // 只做一笔当作第二笔
for (int i = 0; i < n - 1; i++) {
ans = Math.max(ans, left[i] + right[i + 1]);
}
return ans; // (13)
return ans;
}
}

View File

@ -0,0 +1,96 @@
package 实现类功能;
import java.util.Collections;
import java.util.PriorityQueue;
/**
* 题目 295. 数据流的中位数 (partitionMedianFinder)
* 描述中位数是有序整数列表中的中间值如果列表的大小是偶数则没有中间值中位数是两个中间值的平均值
* 例如 arr = [2,3,4] 的中位数是 3
* 例如 arr = [2,3] 的中位数是 (2 + 3) / 2 = 2.5
* 实现 MedianFinder :
* MedianFinder() 初始化 MedianFinder 对象
* void addNum(int num) 将数据流中的整数 num 添加到数据结构中
* double findMedian() 返回到目前为止所有元素的中位数与实际答案相差 10-5 以内的答案将被接受
示例 1
输入
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]
输出
[null, null, null, 1.5, null, 2.0]
解释
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1); // arr = [1]
medianFinder.addNum(2); // arr = [1, 2]
medianFinder.findMedian(); // 返回 1.5 ((1 + 2) / 2)
medianFinder.addNum(3); // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0
* 链接https://leetcode.cn/problems/palindrome-partitioning/
*/
//困难题二刷不会
/**
* 使用一个小顶堆 A存储较大的一半和一个大顶堆 B存储较小的一半并在每次插入后保持以下不变式
* A 的大小 = B 的大小 A 的大小 = B 的大小 + 1
* A 中始终保存较大的一半元素长度为 N/2N 为偶数 (N+1)/2N 为奇数
* B 中始终保存较小的一半元素长度为 N/2N 为偶数 (N1)/2N 为奇数
*/
public class MedianFinder {
// 小顶堆 A保存较大的一半元素
private PriorityQueue<Integer> minHeap;
// 大顶堆 B保存较小的一半元素
private PriorityQueue<Integer> maxHeap;
/** 初始化两个堆 */
public MedianFinder() {
// 默认 Java PriorityQueue 是小顶堆
minHeap = new PriorityQueue<>();
// 传入逆序比较器构造大顶堆
maxHeap = new PriorityQueue<>(Collections.reverseOrder());
}
/**
* 添加一个数到数据结构中
* 1. 先根据与 A 堆顶的大小关系决定插入 A 还是 B
* 2. 然后调整两堆大小使得 size(A)==size(B) size(A)==size(B)+1
* O(log n)
*/
public void addNum(int num) {
// 如果 A 为空 num >= A 的最小值就放入 A否则放入 B
if (minHeap.isEmpty() || num >= minHeap.peek()) {
minHeap.offer(num);
} else {
maxHeap.offer(num);
}
// 平衡如果 A 太大搬一个到 B
if (minHeap.size() > maxHeap.size() + 1) {
maxHeap.offer(minHeap.poll());
}
// 如果 B 太大搬一个到 A
else if (maxHeap.size() > minHeap.size()) {
minHeap.offer(maxHeap.poll());
}
}
/**
* 查找当前所有数的中位数
* - 若总数为奇数A B 1 个元素中位数就是 A 堆顶
* - 若总数为偶数AB 等大中位数是两堆顶元素的平均值
* O(1)
*/
public double findMedian() {
if (minHeap.size() > maxHeap.size()) {
// 奇数个元素中位数在 A
return minHeap.peek();
} else {
// 偶数个元素取平均
return (minHeap.peek() + maxHeap.peek()) / 2.0;
}
}
}