当前位置: 首页 > news >正文

leetcode_56 合并区间

1. 题意

给一个区间集合,求对有交集合的区间合并后的区间。

2. 题解

2.1 排序+双指针

为什么需要对数据进行排序,
为什么是对区间起点进行排序?
对区间终点进行排序行不行?

实际上对于两个区间 [ l 1 , r 1 ] [ l 2 , r 2 ] [l_1,r_1]\ [l_2,r_2] [l1,r1] [l2,r2], 我们只需要他们满足
l 1 ≤ r 2 , l 2 ≤ r 1 l_1 \le r_2, l_2 \le r_1 l1r2,l2r1
两个条件即可。

而无论是按照区间的起点,还是按照区间的终点进行排序。 我们都是在保证其中一个条件。

如果按区间左端点排序,它保证 l 1 ≤ l 2 ∧ l 2 ≤ r 2 ⇒ l 1 ≤ r 2 l_1 \le l_2 \land l_2 \le r_2\Rightarrow l_1 \le r_2 l1l2l2r2l1r2
如果按区间右端点排序,它保证了 r 1 ≤ r 2 ∧ l 1 ≤ r 1 ⇒ l 1 ≤ r 2 r_1 \le r_2 \land l_1 \le r_1 \Rightarrow l_1 \le r_2 r1r2l1r1l1r2

再谈官解里面的正确性证明;为什么存在 a [ i ] , a [ k ] a[i], a[k] a[i],a[k]本应该合并,一定会存在三元组 i , j , k ( i < j < k ) i,j,k(i <j <k) i,j,k(i<j<k), 满足 a [ i ] , a [ j ] a[i],a[j] a[i],a[j]不能合并,且 a [ j ] , a [ k ] a[j],a[k] a[j],a[k]不能合并。

首先 i , k i,k i,k肯定是不相邻的,如果相邻的话就不是异常情况了,所以 i , k i,k i,k之间存在其他整数;

其次为什么一定是 a [ i ] , a [ j ] a[i],a[j] a[i],a[j]不能合并且 a [ j ] , a [ k ] a[j],a[k] a[j],a[k]也不能合并。

因为 a [ i ] , a [ j ] a[i],a[j] a[i],a[j]合并后一定是包含 a [ i ] a[i] a[i],因此必然可以和 a [ k ] a[k] a[k]合并的;
同理 a [ j ] , a [ k ] a[j],a[k] a[j],a[k]合并后一定是包含 a [ k ] a[k] a[k], 因此必然可以和 a [ i ] a[i] a[i]合并的。

因此 a [ j ] a[j] a[j] a [ i ] , a [ k ] a[i],a[k] a[i],a[k]都不能合并。

因此必有
a [ i ] . r < a [ j ] . l a [ j ] . r < a [ k ] . l a[i].r < a[j].l\\ a[j].r <a[k].l a[i].r<a[j].la[j].r<a[k].l
进而
a [ j ] . l < a [ j ] . r a [ i ] . r < a [ k ] . l a[j].l < a[j].r\\ a[i].r < a[k].l a[j].l<a[j].ra[i].r<a[k].l
这与 a [ i ] , a [ k ] a[i],a[k] a[i],a[k]相交
a [ i ] . r ≥ a [ k ] . l a[i].r \ge a[k].l a[i].ra[k].l
矛盾。

按右端点排序时,我们需要反着来处理。

因为正序无法处理[1,2] [3,5] [2,6]这样的情况。

  • 按左端点排序
class Solution {
public:vector<vector<int>> merge(vector<vector<int>>& intervals) {sort( intervals.begin(), intervals.end(), [](const std::vector<int> &a, const std::vector<int> &b){if ( a[0] != b[0])return a[0] < b[0];return a[1] < b[1];});for ( auto it = intervals.begin(); it != intervals.end(); ) {auto lst = it + 1;  while (lst != intervals.end() && (*lst)[0] <= (*it)[1] ) {(*it)[1] = std::max((*it)[1], (*lst)[1]);++lst;}if (lst != it + 1) {it = intervals.erase( it + 1, lst);}else {++it;}}return intervals;}
};
  • 按右端点排序
class Solution {
public:vector<vector<int>> merge(vector<vector<int>>& intervals) {sort( intervals.begin(), intervals.end(),[](const std::vector<int> &a,const std::vector<int> &b){if ( a[1] != b[1]) {return a[1] < b[1];}return a[0] < b[0];});std::vector<std::vector<int>> ans;int sz = intervals.size();int cur = 0;int lst{0};for (int i = intervals.size() - 1;i > -1; i = lst) {cur = i;lst = i - 1;while ( lst > -1 && intervals[cur][0] <= intervals[lst][1]) {intervals[cur][0] = std::min( intervals[cur][0], intervals[lst][0]);--lst;}ans.insert( ans.begin(), intervals[cur]); }return ans;}
};
2.2 差分数组

使用差分数组标记来处理一整片,当出现连续的正数的时候说明是一整个区间。

但有个问题是,似乎无法处理 [ 1 , 2 ] [ 3 , 4 ] [1,2][3,4] [1,2][3,4]这样的情况;

灵之一手的是,直接把区间给扩大到原来两倍,这样不相交区间之间的距离最少就成2了,上面那种情况就不会出现了。

实在是妙!

class Solution {
public:vector<vector<int>> merge(vector<vector<int>>& intervals) {vector<int> diff(2e4+4, 0);int mx = 0;for (auto ints: intervals) {diff[ 2 * ints[0] ]++;diff[ 2 * ints[1] + 1]--;mx = std::max(mx, ints[1]);}int cur = 0;vector< vector<int>> ans;vector<int> tmp(2, 0);for (int i = 0;i <= 2 * mx + 1; ++i) {if ( cur == 0 && diff[i] > 0) {tmp[0] = i / 2;}else if (cur > 0 && (diff[i] + cur == 0) ) {tmp[1] = (i - 1) / 2;ans.push_back( tmp);}cur += diff[ i ];}return ans;}
};

参考

leetcode-官解
03xf的题解

相关文章:

  • 十一.C++ 类 -- 面向对象思想
  • day50 随机函数与广播机制
  • 【西门子杯工业嵌入式-6-ADC采样基础】
  • CMake基础:gcc/g++编译选项详解
  • 结合三维基因建模与智能体技术打造工业软件无码平台
  • 2025-06-08-深度学习网络介绍(语义分割,实例分割,目标检测)
  • 什么是 Ansible 主机和组变量
  • 【数据结构】顺序表和链表详解(下)
  • C++ - string 的使用 #auto #范围for #访问及遍历操作 #容量操作 #修改操作 #其他操作 #非成员函数
  • FBRT-YOLO:面向实时航拍图像检测的轻量高效目标检测框架
  • 股指期货技术分析与短线操作方法介绍
  • 从C到C++语法过度1
  • windows安装Nexus3.6
  • golang循环变量捕获问题​​
  • 网络之交换机
  • InnoDB
  • ubuntu 系统分区注意事项
  • shell批量添加新用户
  • SSE (Server-Sent Events) 技术简介
  • 校园网背后的技术:如何实现全校覆盖与无缝漫游?
  • 小说网站搭建教程/怎么做关键词优化排名
  • 建站之星平台/seo排名优化工具
  • 淮阳住房城乡建设局网站/广西seo
  • 网站运行费用预算/谷歌搜索为什么用不了
  • wordpress 无图主题/百度快照如何优化
  • 企业网站的步骤/管理系统