【leetcode】1751. 最多可以参加的会议数目 II

1751. 最多可以参加的会议数目 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 <= 10^6
  • 1 <= startDayi <= endDayi <= 10^9
  • 1 <= valuei <= 10^6

思路

题目给的events是无序的,可以先排序一下。

这道题类似于背包问题或最长上升子序列。

f[i][j] 表示 前i个会议中,参加最多j个,获得的最大收益。于是我们可以遍历每个会议,分别计算f[i][1...k]能获得的最大利润。

由于参加一个会议需要整个会议的时间,我们可以用当前会议开始的时间去匹配所有会议结束的时间,来查找最早可以开始的时间。这个过程可以使用二分搜索。
Cpp

cpp 复制代码
class Solution {  
public:  
    int maxValue(vector<vector<int>>& events, int k) {  
        ranges::sort(events, {}, [](auto &e){return e[1];});  
        int n = events.size();  
        vector f(n+1, vector(k+1, 0));  // f[i][j] 表示 前i个会议中,参加最多j个,获得的最大收益  
        for (int i = 0; i < n; ++i) { /*遍历会议*/  
            // 二分查找当前这个会议,最早可以在哪个会议结束后,开始  
            int p = lower_bound(events.begin(), events.begin() + i, events[i][0],  
                                [](auto& e, int lower) { return e[1] < lower; }) - events.begin();  
            for (int j = 1; j <= k; ++j) {  
                // 迭代计算前i场会议中,分别参加1~k场可以获得的最大收益  
                f[i+1][j] = max(f[i][j], f[p][j-1] + events[i][2]);  
            }  
        }  
        return f[n][k];  
    }  
};

Golang

go 复制代码
func maxValue(events [][]int, k int) int {
    // 按照结束时间升序排序
    sort.Slice(events, func(i, j int) bool {
        return events[i][1] < events[j][1]
    }) 
    n := len(events)
    // 初始化DP数组:f[i][j]表示前i个会议中参加最多j个会议的最大收益
    f := make([][]int, n+1)
    for i := range f {
        f[i] = make([]int, k+1)
    }

    for i := 0; i < n; i++ {
        // 二分查找:找到结束时间小于当前会议开始时间的最后一个会议
        p := sort.Search(i, func(j int) bool {
            return events[j][1] >= events[i][0]
        })
        // 状态转移
        for j := 1; j <= k; j++ {
            // 选择当前会议:f[p][j-1] + events[i][2]
            // 不选当前会议:f[i][j]
            f[i+1][j] = max(f[i][j], f[p][j-1]+events[i][2])
        }
    }
    return f[n][k]
}
相关推荐
2601_954526754 小时前
【工业传感与算法实战】温漂补偿与零点抗漂破局:基于二阶多项式拟合的 C/C++ 边缘校准算法,深度拆解“压力变送器什么牌子好”的技术硬指标
c语言·c++·算法
叩码以求索5 小时前
浅谈:算法萌新如何高效刷题应对面试(一)
算法·面试·职场和发展
c238566 小时前
把 C++ 内存分配拆透:new 与 malloc 的三层血缘
开发语言·c++·算法
aaaameliaaa7 小时前
指针之总结
c语言·笔记·算法
宵时待雨8 小时前
优选算法专题9:哈希表
数据结构·算法·散列表
txzrxz8 小时前
最短路问题——Dijkstra 算法
数据结构·c++·算法·最短路·优先队列
gwf2168 小时前
磨损均衡算法(Wear Leveling)——SSD如何让每块闪存“公平退休“?
运维·数据库·人工智能·python·嵌入式硬件·算法·智能硬件
noipp8 小时前
推荐题目:洛谷 P6231 [JSOI2013] 公交系统
c语言·数据结构·c++·算法·游戏·洛谷·luogu
c238568 小时前
C/C++每日一练6
c语言·c++·算法
AI小码9 小时前
把动作「画」给视频世界模型,跨本体双向推演,李飞飞参与
大数据·人工智能·算法·ai·大模型·音视频·编程