5.27 买卖股票 + 贪心区间
This commit is contained in:
parent
435ab1b93d
commit
620e720dba
@ -10,7 +10,7 @@ package dynamic_programming;
|
|||||||
输出:2
|
输出:2
|
||||||
解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。
|
解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。
|
||||||
|
|
||||||
* 链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/
|
* 链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iv/
|
||||||
*/
|
*/
|
||||||
//不会
|
//不会
|
||||||
public class MaxProfit4 {
|
public class MaxProfit4 {
|
||||||
|
60
src/main/java/dynamic_programming/MaxProfit5.java
Normal file
60
src/main/java/dynamic_programming/MaxProfit5.java
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package dynamic_programming;
|
||||||
|
/**
|
||||||
|
* 题目: 309. 买卖股票的最佳时机含冷冻期 (maxProfit)
|
||||||
|
* 描述:给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。
|
||||||
|
* 设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
|
||||||
|
* 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
|
||||||
|
* 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
|
||||||
|
|
||||||
|
* 示例 1:
|
||||||
|
输入: prices = [1,2,3,0,2]
|
||||||
|
输出: 3
|
||||||
|
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
|
||||||
|
|
||||||
|
* 链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-cooldown/
|
||||||
|
*/
|
||||||
|
//不会
|
||||||
|
public class MaxProfit5 {
|
||||||
|
public int maxProfit(int[] prices) {
|
||||||
|
int n = prices.length;
|
||||||
|
if (n == 0) return 0;
|
||||||
|
|
||||||
|
// dp[i][0]: 持有股票
|
||||||
|
// dp[i][1]: 不持有,且不在冷冻期(可买入/休息)
|
||||||
|
// dp[i][2]: 今天卖出(刚卖出)
|
||||||
|
// dp[i][3]: 今天冷冻期(昨天卖出)
|
||||||
|
int[][] dp = new int[n][4];
|
||||||
|
|
||||||
|
// 第 0 天的初始状态
|
||||||
|
dp[0][0] = -prices[0]; // 买入
|
||||||
|
dp[0][1] = 0; // 空仓休息
|
||||||
|
dp[0][2] = 0; // 不可能刚卖出
|
||||||
|
dp[0][3] = 0; // 不可能处于冷冻期
|
||||||
|
|
||||||
|
// 从第 1 天开始状态转移
|
||||||
|
for (int i = 1; i < n; i++) {
|
||||||
|
int p = prices[i];
|
||||||
|
|
||||||
|
// 1. 持有股票:要么延续持有,要么从空仓/冷冻期买入
|
||||||
|
dp[i][0] = Math.max(
|
||||||
|
dp[i-1][0],
|
||||||
|
Math.max(dp[i-1][1] - p, dp[i-1][3] - p)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 2. 不持有且不在冷冻期:要么昨儿就休息,要么昨儿冷冻期结束
|
||||||
|
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][3]);
|
||||||
|
|
||||||
|
// 3. 今天卖出:一定是从持有状态卖出
|
||||||
|
dp[i][2] = dp[i-1][0] + p;
|
||||||
|
|
||||||
|
// 4. 今天冷冻期:只能由昨天卖出进入
|
||||||
|
dp[i][3] = dp[i-1][2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最后一天不持有股票的三种状态取最大
|
||||||
|
return Math.max(
|
||||||
|
Math.max(dp[n-1][1], dp[n-1][2]),
|
||||||
|
dp[n-1][3]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
34
src/main/java/dynamic_programming/MaxProfit6.java
Normal file
34
src/main/java/dynamic_programming/MaxProfit6.java
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package dynamic_programming;
|
||||||
|
/**
|
||||||
|
* 题目: 714. 买卖股票的最佳时机含手续费 (maxProfit)
|
||||||
|
* 描述:给定一个整数数组 prices,其中 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
|
||||||
|
|
||||||
|
* 链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/
|
||||||
|
*/
|
||||||
|
public class MaxProfit6 {
|
||||||
|
public int maxProfit(int[] prices, int fee) {
|
||||||
|
int[][]dp=new int[prices.length][2];
|
||||||
|
dp[0][0]=-prices[0]-fee;
|
||||||
|
for (int i = 1; i < prices.length; i++) {
|
||||||
|
dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]-prices[i]-fee);
|
||||||
|
dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
|
||||||
|
}
|
||||||
|
return dp[prices.length-1][1];
|
||||||
|
}
|
||||||
|
}
|
72
src/main/java/range/EraseOverlapIntervals.java
Normal file
72
src/main/java/range/EraseOverlapIntervals.java
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package range;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 题目: 435. 无重叠区间 (eraseOverlapIntervals)
|
||||||
|
* 描述:给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。
|
||||||
|
*
|
||||||
|
* 注意 只在一点上接触的区间是 不重叠的。例如 [1, 2] 和 [2, 3] 是不重叠的。
|
||||||
|
|
||||||
|
* 示例 1:
|
||||||
|
输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
|
||||||
|
输出: 1
|
||||||
|
解释: 移除 [1,3] 后,剩下的区间没有重叠。
|
||||||
|
|
||||||
|
* 链接:https://leetcode.cn/problems/non-overlapping-intervals/
|
||||||
|
*/
|
||||||
|
//不会
|
||||||
|
public class EraseOverlapIntervals {
|
||||||
|
/**
|
||||||
|
* 1.按结束时间排序
|
||||||
|
* 对所有区间按它们的右端点(end)从小到大排序。
|
||||||
|
* 这样,我们每次选取能最早「结束」的区间,就能给后面留下最大的空间,容纳更多不重叠的区间。
|
||||||
|
*
|
||||||
|
* 2.一次线性扫描,维护「当前结束」
|
||||||
|
* 用变量 end 记录上一次加入的(未移除的)区间的结束位置,初始化为排序后第一个区间的结束。
|
||||||
|
* 用 count 记录当前保留下来的不重叠区间数量,初始化为 1(第一个区间肯定留下)。
|
||||||
|
* 从第二个区间开始遍历:
|
||||||
|
* 如果当前区间的起点 start ≥ end,说明它与上一次保留的区间不重叠,可以「保留」:
|
||||||
|
* count++,并更新 end = 当前区间的 end。
|
||||||
|
* 否则,它与上一次保留的区间发生重叠,必须移除其中一个。
|
||||||
|
* 为了让后续更容易接上,我们应当移除「结束得更晚」的那个区间,也就是保留结束更早的那个(即当前排序中的那个已经在保留的区间),此时不更新 end,相当于跳过(移除)当前区间。
|
||||||
|
*
|
||||||
|
* 3.计算需移除的数量
|
||||||
|
* 最终保留下来的区间数为 count,总区间数为 n,所以最少要移除 n - count 个。
|
||||||
|
* @param intervals
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int eraseOverlapIntervals(int[][] intervals) {
|
||||||
|
//0,3 2,5 4,7
|
||||||
|
int n = intervals.length;
|
||||||
|
if (n == 0) {
|
||||||
|
// 没有区间,当然不需要移除
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 按照区间的结束时间(end)从小到大排序
|
||||||
|
Arrays.sort(intervals, (a, b) -> Integer.compare(a[1], b[1]));
|
||||||
|
|
||||||
|
// 2. 初始化:保留第一个区间
|
||||||
|
int count = 1; // 当前保留的不重叠区间数量
|
||||||
|
int end = intervals[0][1]; // 最近一次保留区间的结束时间
|
||||||
|
|
||||||
|
// 3. 遍历其余区间
|
||||||
|
for (int i = 1; i < n; i++) {
|
||||||
|
int startI = intervals[i][0];
|
||||||
|
int endI = intervals[i][1];
|
||||||
|
|
||||||
|
if (startI >= end) {
|
||||||
|
// 不重叠:可以保留
|
||||||
|
count++;
|
||||||
|
end = endI; // 更新「最近一次保留区间」的结束时间
|
||||||
|
}
|
||||||
|
// 否则:重叠。移除「结束更晚」的那个区间。
|
||||||
|
// 因为我们是按 end 升序遍历的,当前 intervals[i] 的 end ≥ end,
|
||||||
|
// 所以移除它即可;无需更新 end。
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 最少移除数 = 总数 - 保留下来的数量
|
||||||
|
return n - count;
|
||||||
|
}
|
||||||
|
}
|
@ -19,16 +19,41 @@ import java.util.HashMap;
|
|||||||
* 链接:https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/
|
* 链接:https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/
|
||||||
*/
|
*/
|
||||||
public class FindMinArrowShots {
|
public class FindMinArrowShots {
|
||||||
|
/**
|
||||||
|
* 一种经典做法是:先按照每个气球的 右端点 从小到大排序;
|
||||||
|
* 然后从最左边的气球开始,选它的右端点作为射箭位置,这样能保证这支箭能戳破尽可能多的 “覆盖” 当前右端点的气球;
|
||||||
|
* 跳过所有已经被这支箭打到的气球,再对下一个未被覆盖的气球重复相同操作。
|
||||||
|
* @param points
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public int findMinArrowShots(int[][] points) {
|
public int findMinArrowShots(int[][] points) {
|
||||||
|
int n = points.length;
|
||||||
|
if (n == 0) {
|
||||||
|
// 没有气球,当然不用射箭
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 按照区间的右端点从小到大排序
|
||||||
|
// 这样每次选当前最小的右端点作为射箭位置,
|
||||||
|
// 能最大程度地覆盖后续尽可能多的气球
|
||||||
Arrays.sort(points, (a, b) -> Integer.compare(a[1], b[1]));
|
Arrays.sort(points, (a, b) -> Integer.compare(a[1], b[1]));
|
||||||
|
|
||||||
int index=0,cnt=0;
|
int cnt = 0; // 箭的数量
|
||||||
while(index<points.length){
|
int index = 0; // 当前未覆盖的气球下标
|
||||||
int temp=index;
|
|
||||||
while(index<points.length&&points[temp][1]>=points[index][0])
|
// 2. 遍历所有气球,只要还有未戳破的,就再射一支箭
|
||||||
index++;
|
while (index < n) {
|
||||||
|
// 这一支箭射在 points[index][1] 处(当前未处理区间的最小右端)
|
||||||
|
int shootPos = points[index][1];
|
||||||
cnt++;
|
cnt++;
|
||||||
|
|
||||||
|
// 3. 跳过所有能够被这支箭戳破的气球
|
||||||
|
// 条件:它们的左端 ≤ shootPos
|
||||||
|
while (index < n && points[index][0] <= shootPos) {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
src/test/java/dynamic_programming/MaxProfit6Test.java
Normal file
17
src/test/java/dynamic_programming/MaxProfit6Test.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package dynamic_programming;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class MaxProfit6Test {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void maxProfit() {
|
||||||
|
int[]prices = {1,3,7,5,10,3};
|
||||||
|
int fee = 3;
|
||||||
|
MaxProfit6 maxProfit6 = new MaxProfit6();
|
||||||
|
int res=maxProfit6.maxProfit(prices,fee);
|
||||||
|
System.out.println(res);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user