神机百炼1.20-区间合并

区间合并导图

食用指南:

对该算法程序编写以及踩坑点很熟悉的同学可以直接跳转到代码模板查看完整代码
只有基础算法的题目会有关于该算法的原理,实现步骤,代码注意点,代码模板,代码误区的讲解
非基础算法的题目侧重题目分析,代码实现,以及必要的代码理解误区

题目描述:

  • 给定 n 个区间 [li,ri],要求合并所有有交集的区间。
    注意如果在端点处相交,也算有交集。
    输出合并完成后的区间个数。
    例如:[1,3] 和 [2,6] 可以合并为一个区间 [1,6]。

    输入格式
    第一行包含整数 n。
    接下来 n 行,每行包含两个整数 l 和 r。

    输出格式
    共一行,包含一个整数,表示合并区间完成后的区间个数。

    数据范围
    1≤n≤100000,
    −109≤li≤ri≤109
    输入样例:
    5
    1 2
    2 4
    5 6
    7 8
    7 9
    输出样例:
    3

  • 题目来源:https://www.acwing.com/problem/content/805/

题目分析:

  • 十万个区间,每个区间最值都在1亿,int解决

  • 经典区间合并算法

  • 以vector<pair<int, int>>存储区间

    以左端点排序所有区间

    每次只需要比较当前区间左端点和上一个区间右端点大小,即可完成区间合并

    也有离散化的痕迹,但是不如纯离散化题那么难,回顾离散化:传送门
    当然也有贪心的意思,很多区间贪心改编于此,我们之后会讲贪心

算法原理:

1. 区间合并:

  • 判断两个区间是否可以合并只看上一区间右端点和这一区间左端点大小关系
  1. r1 >= L2:可合并,新区间左端点L1,右端点r2,区间个数不变
    可合并

  2. r1 < L2:不可合并,区间个数++
    不可合并

2. vector的sort():

  • vector<int>

    1. 升序:sort(vec.begin(), vec.end());
      写完全其实是sort(vec.begin(), vec,end(), less());
    2. 降序:sort(vec.begin(), vec,end(), greater());
  • vector<pair<int, int>>

    默认以pair<int ,int>的first进行排序

    1. 升序:sort(start, end);
    2. 降序:sort(start, end,greater<pair<int,int>>);

    手动实现bool cmp()达到以pair的second排序

static bool cmp(const pair<int, int>& a, const pair<int, int>& b)
{
	//升序
	return a.second > b.second;
	//降序
	return a.second > b.second;
}

存储形式:

  • 区间:pair<int, int>
  • 区间向量/数组:vector<pair<int ,int>>
  • 当前区间左端点:l,初始化负无穷
  • 当前区间右端点:r,初始化负无穷
  • l & r 是区间合并的辅助变量,也可以说是双指针了传送门

代码实现:

typedef pair<int,int> PII;
vector<PII> segs;
int merge(){
	vector<PII> res;
    sort(segs.begin(), segs.end());
    int l = -2e9, r = -2e9;
    //辅助记录变量需要足够小,让第一个线段肯定加入
    for(auto seg: segs){
		if(seg.first > r){
			if (l != -2e9)
                res.push_back({l,r});
           	l = seg.first;
            r = seg.second;
        }else{
			r = max(r, seg.second);
        }
    }
    return res;
}
int main(){
    int n=0;
    cin>>n;
    whle(n--){
		int l = 0, r = 0;
    	cin >>l >>r;
        segs.push_back({l,r});
    }
    cout <<merge().size()<<endl;
	return 0;
}

代码误区:

1. 区间合并最难的地方是什么?

  • 区间可否合并的判断并不难,难在l r双指针辅助变量的设立
  • 合并条件可以现想,但是l r只有代码写的难受了才会发现

2. 区间合并易漏点:

  • 没有以左端点进行排序,就开始合并
    • 要记区间合并,就记排序 + 双指针

本篇感想:

  • 区间合并本身很简单,拓展比较多,有时候比较隐蔽,需要有区间合并试试的想法

  • 第二十篇神机百炼完成,距离”百炼“越来越近了啊,哈哈。等100篇的时候会从神机百炼拓展到更多的编程技术,有兴趣可以猜猜语言教学专栏叫什么。

  • 美图一张
    夏-小有所成

  • 看完本篇博客,恭喜已登 《练气境-中期
    练气期初阶
    距离登仙境不远了,加油 登仙境初期

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starnight531

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值