ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LeetCode/区间合并和日程表

2022-06-13 04:00:20  阅读:158  来源: 互联网

标签:cnt end 日程表 int 合并 start ans 区间 LeetCode


1. 静态区间合并

先按左边界排序,再两两比较合并

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        if (intervals.size() == 0) return {};
        sort(intervals.begin(), intervals.end());//按左边界排序
        vector<vector<int>> merged;//需要空间存储合并结果
        for (int i = 0; i < intervals.size(); ++i) {
            int L = intervals[i][0], R = intervals[i][1];
            //如果存储空间没有元素,或末元素右边界小于新元素左边界,加入区间
            if (!merged.size() || merged.back()[1] < L) 
                merged.push_back({L, R});
            //否则进行合并,右边界更新为两合并元素较大值
            else  merged.back()[1] = max(merged.back()[1], R);
        }
        return merged;
    }
};

2. 我的日程安排表I

如果可以将日程(区间)安排成功添加到日历(区间集合)中而不会导致重复预订(存在交集)
返回 true ,否则,返回 false 并且不要将该日程安排添加到日历中

暴力法

将新加入区间,与已有区间逐个比较,判断有无交集即可

暴力法
vector<pair<int, int>> vec;
bool book(int start, int end) {
        for (auto& [x, y] : vec)//遍历已存储所有的区间
            if (x < end && y > start) return false;//判断新加入区间是否有交集
        vec.emplace_back(pair{start, end});//存储新的区间
        return true;
    }
暴力法优化(二分)

使用map存储区间,利用其有序的结构特点,进行二分查找并比较

map+二分
class MyCalendar {
public:
    map<int, int> pool;
    MyCalendar() {}
    
    bool book(int start, int end) {
        // lower_bound()返回值是一个迭代器,返回指向左边界>=end的第一个值的位置
        map<int, int>::iterator it = pool.lower_bound(end);//二分查找需要比较的位置,是得到位置的前一个位置
        // 判断是否为第一个元素,或前一个元素的结束时间<= start
        if (it == pool.begin() || (--it)->second <= start) {//右边界在所有区间左侧或者左边界在前一个元素右边界之后
            pool[start] = end;//插入该区间
            return true;
        }
        return false;
    }
};
插旗法

通过插旗计数来验证左边界前的区间是否闭合,以及是否有位置落在新加入区间之间
使用map结构自动排序

插旗法
class MyCalendar {
public:
    MyCalendar() {}
    bool book(int start, int end) {
        int ans = 0;
        int left = 0;//从前往后计数值
        for (auto &[pos, freq] : cnt) {
            if(pos<=start) left += freq; //计前缀和
            else if(pos<end) return false;//说明start和end间必然存在其他区间
        }
        if(left==0){ //如果计数为0说明前面区间皆已闭合
        //插入新区间
            cnt[start]++;//起点加一
            cnt[end]--;//终点减一 
            return true;}
        else return false;
    }
private:
    map<int, int> cnt;//这里使用map自动排序
};

3. 我的日程安排表II(插旗法)

如果要添加的时间内不会导致三重预订时,则可以存储这个新的日程安排
这里我们不用去判断,直接尝试加入,看累加值是否会等于3即可,注意插入失败即时撤回

    bool book(int start, int end) {
        int ans = 0;
        cnt[start]++;//起点加一,先尝试加入
        cnt[end]--;//终点减一
        for (auto &[pos, freq] : cnt) {
            ans += freq; //从前往后累加
            if(ans==3){cnt[start]--;cnt[end]++;return false;}//撤回并返回插入失败
        }
        return true;
    }

4. 我的日程安排表III(插旗法)

从前往后求差分数组前缀和的时候,记录一个最大值即可

int book(int start, int end) {
        int ans = 0;
        int maxBook = 0;
        cnt[start]++;//起点加一
        cnt[end]--;//终点减一
        for (auto &[_, freq] : cnt) {
            maxBook += freq; //从前往后累加
            ans = max(maxBook, ans); //记录最大值
        }
        return ans;
    }

标签:cnt,end,日程表,int,合并,start,ans,区间,LeetCode
来源: https://www.cnblogs.com/929code/p/16369464.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有