• 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;
        }
    
  • 相关阅读:
    (转)使用介质设备安装 AIX 以通过 HMC 安装分区
    (转)在 VMware 中安装 HMC
    (转)50-100台中小规模网站集群搭建实战项目(超实用企业集群)
    (转)awk数组详解及企业实战案例
    (转) IP子网划分
    教你如何迅速秒杀掉:99%的海量数据处理面试题(转)
    PHP对大文件的处理思路
    十道海量数据处理面试题与十个方法大总结
    mysql查询更新时的锁表机制分析
    mysql数据库问答
  • 原文地址:https://www.cnblogs.com/929code/p/16369464.html
Copyright © 2020-2023  润新知