7.16 股票买卖
This commit is contained in:
parent
8c8f0d0b20
commit
dbd0be69e8
@ -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;
|
||||
|
@ -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天持有股票时的最大收益
|
||||
|
@ -16,6 +16,7 @@ package dynamic_programming;
|
||||
* 链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/
|
||||
*/
|
||||
//不会
|
||||
//二刷不会
|
||||
public class MaxProfit3 {
|
||||
/**
|
||||
* 一天一共就有五个状态,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,利润 = 6−2 = 4。
|
||||
* 以 i=1(价格 5)为起点:未来最高同样 6,利润 = 6−5 = 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]: 0…i 天内最多一笔交易的最优收益
|
||||
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]: i…n-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;
|
||||
}
|
||||
}
|
||||
|
96
src/main/java/实现类功能/MedianFinder.java
Normal file
96
src/main/java/实现类功能/MedianFinder.java
Normal 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/2(N 为偶数)或 (N+1)/2(N 为奇数)。
|
||||
* B 中始终保存「较小的一半」元素,长度为 N/2(N 为偶数)或 (N–1)/2(N 为奇数)。
|
||||
*/
|
||||
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 堆顶
|
||||
* - 若总数为偶数:A、B 等大,中位数是两堆顶元素的平均值
|
||||
* O(1)
|
||||
*/
|
||||
public double findMedian() {
|
||||
if (minHeap.size() > maxHeap.size()) {
|
||||
// 奇数个元素,中位数在 A
|
||||
return minHeap.peek();
|
||||
} else {
|
||||
// 偶数个元素,取平均
|
||||
return (minHeap.peek() + maxHeap.peek()) / 2.0;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user