两个最好的不重叠活动
难度:
标签:
题目描述
给你一个下标从 0 开始的二维整数数组 events
,其中 events[i] = [startTimei, endTimei, valuei]
。第 i
个活动开始于 startTimei
,结束于 endTimei
,如果你参加这个活动,那么你可以得到价值 valuei
。你 最多 可以参加 两个时间不重叠 活动,使得它们的价值之和 最大 。
请你返回价值之和的 最大值 。
注意,活动的开始时间和结束时间是 包括 在活动时间内的,也就是说,你不能参加两个活动且它们之一的开始时间等于另一个活动的结束时间。更具体的,如果你参加一个活动,且结束时间为 t
,那么下一个活动必须在 t + 1
或之后的时间开始。
示例 1:
输入:events = [[1,3,2],[4,5,2],[2,4,3]] 输出:4 解释:选择绿色的活动 0 和 1 ,价值之和为 2 + 2 = 4 。
示例 2:
输入:events = [[1,3,2],[4,5,2],[1,5,5]] 输出:5 解释:选择活动 2 ,价值和为 5 。
示例 3:
输入:events = [[1,5,3],[1,5,1],[6,6,5]] 输出:8 解释:选择活动 0 和 2 ,价值之和为 3 + 5 = 8 。
提示:
2 <= events.length <= 105
events[i].length == 3
1 <= startTimei <= endTimei <= 109
1 <= valuei <= 106
代码结果
运行时间: 188 ms, 内存: 53.0 MB
/*
思路:
1. 首先对所有活动按结束时间排序,以便于我们可以找到不重叠的活动。
2. 使用 Java Stream 的方式来实现动态规划和二分查找的功能。
3. 对于每个活动,找到最后一个不与之重叠的活动,然后决定是否选择该活动。
4. 如果选择当前活动,则最大价值为当前活动的价值加上前一个不冲突的活动的最大值。
5. 返回最大价值。
*/
import java.util.*;
import java.util.stream.IntStream;
public class MaxValueEventsStream {
public int maxTwoEvents(int[][] events) {
Arrays.sort(events, Comparator.comparingInt(a -> a[1])); // 按结束时间排序
int n = events.length;
int[] dp = new int[n];
dp[0] = events[0][2];
int max = dp[0];
for (int i = 1; i < n; i++) {
int currentValue = events[i][2];
int lastIndex = IntStream.range(0, i)
.filter(j -> events[j][1] < events[i][0])
.reduce((a, b) -> b)
.orElse(-1);
if (lastIndex != -1) {
currentValue += dp[lastIndex];
}
dp[i] = Math.max(dp[i - 1], currentValue);
max = Math.max(max, dp[i]);
}
return max;
}
}
解释
方法:
该题解采用排序和扫描的方法来寻找最大的价值和。首先,原始活动列表按照活动的开始时间进行排序,同时创建一个以结束时间排序的活动列表。通过这两个排序列表,算法试图找到不重叠的最佳两个活动组合。使用一个指针 'left' 来遍历按结束时间排序的列表,而主循环遍历按开始时间排序的列表。在主循环中,对于每个活动,我们使用 'left' 指针移动到所有结束时间早于当前活动开始时间的活动,并更新这些活动中的最大价值 'pre_max'。然后,将当前活动的价值加上这个 'pre_max',并更新整体的最大价值 'ans'。
时间复杂度:
O(n log n)
空间复杂度:
O(n)
代码细节讲解
🦆
题解中提到的‘left’指针是如何确保在遍历过程中始终指向有效的、不与当前活动重叠的活动?请详细解释其逻辑。
▷🦆
在更新‘pre_max’的过程中,是否有可能出现遗漏某个活动的情况?如果有,算法是如何处理这种情况的?
▷🦆
算法是否考虑了只参加一个活动的情况?如果是,该逻辑是如何实现的?
▷