贪心算法之合并区间

"任世界多宽广,停泊在这港口~"


区间问题,涉及到最多的就是 取交集 和 并集的概念。我们使用C++排序算法后,其默认规则就是按照 "左排序"进行的。因而,我们实质上注意的是每一个区间的 右端点,根据题目要求,总结规律,指定出策略解决问题。

合并区间

(1) 题目解析

(2) 算法原理

cpp 复制代码
class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        sort(intervals.begin(),intervals.end());
        vector<vector<int>> res;
        int n = intervals.size();
        // 取左右端点
        int left = intervals[0][0],right = intervals[0][1];
        for(int i=1;i<n;++i)
        {
            int a = intervals[i][0],b = intervals[i][1];
            if(a <= right){
                // 有重合区间
                right = max(right,b);
            }
            else
            {
                // 更新
                res.push_back({left,right});
                left = a;
                right = b;
            }
        }
        // 最后一组 区间 也需要被插入
        res.push_back({left,right});
        return res;
    }
};

证明:

因为,我们默认了排完序之后,所有的左端点,能合并的,都是连续的。所以,我们使用反证法设:左端点排完序后,不连续

所以,我们按照左端点排完序后,一旦将区间合并,那么其一顶是连续的。

无重叠区间

(1) 题目解析

(2) 算法原理

cpp 复制代码
class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        sort(intervals.begin(),intervals.end());
        int n = intervals.size();
        int ret = 0;
        int left = intervals[0][0],right = intervals[0][1];
        for(int i=1;i<n;++i){
            int a = intervals[i][0],b = intervals[i][1];
            if(a < right){
                // 存在重叠 保留小范围的
                ret++;
                right = min(right,b);
            }
            else{
                // 不存在重叠 新的开始
                right = b;
            }
        }
        return ret;
    }
};

证明:

这样的贪心策略是否正确呢 ?我们假设贪心解是错误的。所以,我们会得到两份答案,一份是贪心解,一份是最有解:

⽤最少数量的箭引爆⽓球

(1) 题目解析

(2) 算法原理

cpp 复制代码
class Solution {
public:
    int findMinArrowShots(vector<vector<int>>& points) {
        sort(points.begin(),points.end());
        int n = points.size();
        int left = points[0][0],right = points[0][1];
        int ret = 1; // 第一个区间就需要引爆
        for(int i=1;i<n;++i)
        {
            int a = points[i][0],b = points[i][1];
            if(a <= right)
            {
                // 重叠的 可以一支箭引爆
                right = min(right,b);
            }
            else
            {
                ret++; // 不是重叠 需要一支箭引爆
                right = b;
            }
        }
        return ret;
    }
};

本篇到此结束,感谢你的阅读。

祝你好运,向阳而生~

相关推荐
程序猿炎义1 天前
【Easy-VectorDB】Faiss数据结构与索引类型
数据结构·算法·faiss
天赐学c语言1 天前
1.20 - x的平方根 && vector的扩容机制以及删除元素是否会释放内存
c++·算法·leecode
52Hz1181 天前
力扣24.两两交换链表中的节点、25.K个一组反转链表
算法·leetcode·链表
老鼠只爱大米1 天前
LeetCode经典算法面试题 #160:相交链表(双指针法、长度差法等多种方法详细解析)
算法·leetcode·链表·双指针·相交链表·长度差法
ValhallaCoder1 天前
Day53-图论
数据结构·python·算法·图论
老鼠只爱大米1 天前
LeetCode经典算法面试题 #84:柱状图中最大的矩形(单调栈、分治法等四种方法详细解析)
算法·leetcode·动态规划·单调栈·分治法·柱状图最大矩形
C雨后彩虹1 天前
羊、狼、农夫过河
java·数据结构·算法·华为·面试
重生之后端学习1 天前
19. 删除链表的倒数第 N 个结点
java·数据结构·算法·leetcode·职场和发展
aini_lovee1 天前
严格耦合波(RCWA)方法计算麦克斯韦方程数值解的MATLAB实现
数据结构·算法·matlab
安特尼1 天前
推荐算法手撕集合(持续更新)
人工智能·算法·机器学习·推荐算法