1751. 最多可以参加的会议数目 II hard
【参考:1751. 最多可以参加的会议数目 II - 力扣(LeetCode)】
【参考:【阿飞算法】畅游面试中的动态规划套路-最多可以参加的会议数目 II - 最多可以参加的会议数目 II - 力扣(LeetCode)】 循序渐进
- 自顶向下记忆化递归
memo[curr][k] : 表示处理到编号curr这个会议,还剩余k次参加会议机会所能获取的价值的最大值
class Solution {
int[][] memo;
public int maxValue(int[][] events, int k) {
int n=events.length;
// 因为递归是自顶向下,所以按照开始时间排序
Arrays.sort(events,(int[] a,int[] b)-> {return a[0]-b[0];});
memo=new int[n][k+1]; // 会议数量[0,n-1],能参加的最多会议数目[1,k]
int res=helper(events,0,n,k); // 从第一个会议开始 注意下标为0
return res;
}
// cur 当前的会议编号[0,n-1], n 会议数量, k 剩余参加次数 [1,k]
int helper(int[][] events,int cur,int n,int k){
// 出口 cur到达末尾 或者 剩余参加次数用完了
if(cur==n || k==0) return 0;
// 查表
if(memo[cur][k]!=0) return memo[cur][k];
// 从前往后找 找到第一个开始时间大于cur的结束时间的会议编号i (可以二分来加速)
int i=0;
for(i=cur+1;i<n;i++){
if (events[i][0] > events[cur][1]) break;
}
// 参加编号为cur的会议,剩余参加次数-1,下个会议是i
int join=helper(events,i,n,k-1) + events[cur][2]; // 加上这个会议的value
// 不参加编号为cur的会议,下一个会议是cur+1
int joinNo=helper(events,cur+1,n,k);
int ans=Math.max(join,joinNo); // 取最大值
memo[cur][k]=ans;// 填充表格
return memo[cur][k];
}
}
- dp
待深化理解
class Solution {
public int maxValue(int[][] events, int k) {
int n = events.length;
// 因为我们要找 p,我们需要先对 events 的结束时间排序,然后找从右往左找,找到第一个满足 结束时间 小于 当前事件的开始时间 的事件,就是 last
Arrays.sort(events, (o1, o2) -> o1[1] - o2[1]);
//`dp[i][j]`表示在前`i`个会议中,最多只能参加`j`个会议,所能获取到的最大价值
int[][] dp = new int[n + 1][k + 1];
for (int i = 1; i <= n; i++) {
int[] curr = events[i - 1];
int start = curr[0], end = curr[1], value = curr[2];
// [i+1..n]会议已经遍历过了
// 从右往左找 最靠近i的且其结束时间比i的开始时间小的那个会议,记为p
int p=0;
for (p=i-1;p>=1;p--){
if(events[p-1][1] < start) break;
}
//遍历前这 k次参加会议的机会
for (int j = 1; j <= k; j++) {
dp[i][j] = Math.max(dp[i - 1][j], // 不参加当前i会议
dp[p][j - 1] + value); // 参加当前i 会议
}
}
return dp[n][k];
}
}