最多可以参加的会议数目 II
难度:
标签:
题目描述
给你一个 events
数组,其中 events[i] = [startDayi, endDayi, valuei]
,表示第 i
个会议在 startDayi
天开始,第 endDayi
天结束,如果你参加这个会议,你能得到价值 valuei
。同时给你一个整数 k
表示你能参加的最多会议数目。
你同一时间只能参加一个会议。如果你选择参加某个会议,那么你必须 完整 地参加完这个会议。会议结束日期是包含在会议内的,也就是说你不能同时参加一个开始日期与另一个结束日期相同的两个会议。
请你返回能得到的会议价值 最大和 。
示例 1:
输入:events = [[1,2,4],[3,4,3],[2,3,1]], k = 2 输出:7 解释:选择绿色的活动会议 0 和 1,得到总价值和为 4 + 3 = 7 。
示例 2:
输入:events = [[1,2,4],[3,4,3],[2,3,10]], k = 2 输出:10 解释:参加会议 2 ,得到价值和为 10 。 你没法再参加别的会议了,因为跟会议 2 有重叠。你 不 需要参加满 k 个会议。
示例 3:
输入:events = [[1,1,1],[2,2,2],[3,3,3],[4,4,4]], k = 3 输出:9 解释:尽管会议互不重叠,你只能参加 3 个会议,所以选择价值最大的 3 个会议。
提示:
1 <= k <= events.length
1 <= k * events.length <= 106
1 <= startDayi <= endDayi <= 109
1 <= valuei <= 106
代码结果
运行时间: 562 ms, 内存: 90.0 MB
/*
* 思路:
* 1. 将会议按结束时间排序。
* 2. 使用动态规划解决问题,dp[i][j] 表示参加前 i 个会议中最多参加 j 个会议的最大价值。
* 3. 对于每个会议,决定是否参加。如果参加,找到上一个不冲突的会议,更新dp。
* 4. 使用Java Stream API进行部分操作。
*/
import java.util.Arrays;
import java.util.stream.IntStream;
public class SolutionStream {
public int maxValue(int[][] events, int k) {
Arrays.sort(events, (a, b) -> Integer.compare(a[1], b[1]));
int n = events.length;
int[][] dp = new int[n + 1][k + 1];
IntStream.rangeClosed(1, n).forEach(i -> {
int prev = findPrevious(events, i - 1);
IntStream.rangeClosed(1, k).forEach(j -> {
dp[i][j] = Math.max(dp[i - 1][j], dp[prev + 1][j - 1] + events[i - 1][2]);
});
});
return dp[n][k];
}
private int findPrevious(int[][] events, int index) {
int start = events[index][0];
return IntStream.range(0, index)
.map(i -> index - 1 - i)
.filter(i -> events[i][1] < start)
.findFirst()
.orElse(-1);
}
}
解释
方法:
该题解主要使用了动态规划的方法来解决问题。首先,将事件按照结束时间进行排序,以保证在处理事件的顺序时可以按照时间的顺序来处理。定义一个二维的dp数组,其中dp[i][j]代表考虑前i个事件,最多参加j个事件时能获得的最大价值。对于每一个事件,我们可以选择参加或不参加。如果不参加,则最大价值与前i-1个事件选择j个的价值相同,即dp[i][j] = dp[i-1][j]。如果选择参加,我们需要找到在该事件开始之前结束的最晚的事件,这可以通过从当前事件向前搜索,找到第一个结束时间小于当前事件开始时间的事件来实现。如果找到这样的事件,参加当前事件的价值是该事件的价值加上在找到的事件之前的最大价值,即dp[i][j] = max(dp[i][j], dp[last+1][j-1] + value)。最终,dp[n][k]中存储的就是在所有事件中选择最多k个事件能得到的最大价值。
时间复杂度:
O(n^2 * k)
空间复杂度:
O(n * k)
代码细节讲解
🦆
请问在寻找`在该事件开始之前结束的最晚的事件`时,简单地遍历前面所有事件是否效率最优?是否有更高效的方法来找到这个事件?
▷🦆
在动态规划的转移方程中,为什么选择`dp[last + 1][j - 1] + val`作为参加当前事件时的状态更新?这里的`last + 1`代表什么意义?
▷🦆
在初始化dp数组时,所有元素都被初始化为0。这是否适用于所有情况,即使有些会议的价值为负数?
▷