关于线段的算法汇总
来源:互联网 发布:淘宝智能机器人好用吗 编辑:程序博客网 时间:2024/06/14 21:20
基本知识:
线段树:存储线段的二叉排序树,以start作为key, 同时维护树中最大的右端点值 max
class Node { int start; int end; int max;}经典应用:query any interval that intersect(overlap) with a given interval. 如果是查询所有与给定线段重合的线段,则查到一个,从树种删去,再查。最后再插回来。复杂度为RlgN
区间树:区间[l, r]的左右子树分别为[l, (l + r) / 2], [(l + r) / 2 + 1, r],叶节点都是一个元素的区间[a,a]。主要用于查询区间上的属性,比如和,最大值最小值,满足某种条件的元素个数等。
经典应用,给定一个数组,需要高效的查询任意区间的和(最大值,满足某种条件的元素个数等)。对区间建立区间树,然后每次查询都是lgN的。原理是这样,原区间的值,都都是由左右两个子区间的值得来的,类似merge,比如求整个区间的和,可以分别求左右区间的和,然后相加。这是一个递归的过程,递归到只有一个元素。当区间只有一个元素时,和、最大值等都是自己。
一些经典题目:
1. 给定一组飞机的起飞和降落时间,问同时最多几架飞机在飞行?类似的问法,一组火车出发到达时刻表,问最多同时几趟火车在运行?一组括号中最多几层嵌套?
solution:经典的扫描线法,把线段(start, end)拆成点(time, start/end),排序,如果时间值相同,终点在前起点在后。遇到一个起点count++,遇到一个终点count --。
int countOfAirplanes(vector<Interval> &airplanes) { vector<pair<int, int>> times; for (auto &it : airplanes) { times.push_back(make_pair(it.start, 1)); times.push_back(make_pair(it.end, 0)); } sort(times.begin(), times.end()); int maxNum = 0, curNum = 0; for (auto &t : times) { if (t.second == 1) curNum++; else curNum--; maxNum = max(maxNum, curNum); } return maxNum;}
2. 给定一组线段,对线段进行merge
solution: 按起点排序,
循环不变式:result 是一个merge过有序的线段列表,初始化就是第一个线段。当前线段跟result.里最后一个线段比,当前线段的start肯定晚于result.back()的start, 因为之前已经按start排过序,主要看是否和其end相交:
1)如果小于等于其end,说明有相交,只需要更新上一个选段的终点 result.back().end = max(result.back().end, cur.end())
2)否则不想交,直接append到result里
vector<Interval> merge(vector<Interval> &intervals) {if (intervals.empty()) return intervals;sort(intervals.begin(), intervals.end(),[](Interval a, Interval b) -> bool { return a.start < b.start;});vector<Interval> output(1, intervals[0]);for(int i = 1; i < intervals.size(); i++) {if (intervals[i].start <= output.back().end)output.back().end = max(output.back().end, intervals[i].end);elseoutput.push_back(intervals[i]);}return output;}
3 给定一组不想交排好序的线段,把一个线段插入其中,并进行必要的merge
思路
1)跳过在前面的、不相交的线段:新线段起点在其终点后面
2)处理重合的,更新线段的起、终点,并且删除原线段:重合条件:新线段终点大于等于其起点(之前已经保证了新线段起点早于其终点)
3)append后面的不相交的线段
版本一:原地插入
vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) {auto i = intervals.begin();while (i != intervals.end() && newInterval.start > i->end) i++;while (i != intervals.end() && newInterval.end >= i->start) {newInterval.start = min(newInterval.start, i->start);newInterval.end = max(newInterval.end, i->end);i = intervals.erase(i);}intervals.insert(i, newInterval);return intervals;}
版本二:用另一个列表保存结果
public ArrayList<Interval> insert(ArrayList<Interval> intervals, Interval newInterval) {ArrayList<Interval> result = new ArrayList<Interval>();int i = 0;// proceding intervalswhile (i < intervals.size() && intervals.get(i).end < newInterval.start) {result.add(intervals.get(i));i++;}//overlaping intervals, just keeps a longest onefor (; i < intervals.size() && intervals.get(i).start <= newInterval.end; i++) {newInterval.start = Math.min(newInterval.start, intervals.get(i).start);newInterval.end = Math.max(newInterval.end, intervals.get(i).end);}result.add(newInterval);// intervals going behindfor (; i < intervals.size(); i++)result.add(intervals.get(i));return result;}
4 带颜色的刷线段问题,输入是一系列把一个区间刷成某种颜色的操作,(start, end, color),输出最后的状态
分析;和insert 线段有点像,分三个部分:
1)首先要skip前面不相交的部分,toInsert.start > intervals[i].end || toInsert.start == intervals[i].end && toInsert.color != intervals[i].color,这里的条件稍有不同,和上一个线段的end刚好连上,但是颜色不同,也skip。
2) merge的部分:不带颜色的线段的merge,overlap的部分连在一起,就是保留一个最长的线段。带颜色的话,可能是生成1个,2个,3个,两头部分覆盖,中间完全覆盖
3)后面不相交的部分,toInsert.end < intervals[i].start || toInsert.end == intervals[i].start && toInsert.color != intervals[i]
- 关于线段的算法汇总
- 线段的拾取算法
- 线段的裁剪算法
- 一定要做的线段树习题汇总
- 关于线段树的update
- 求点到线段的近似算法
- (第20讲)关于排序的各种算法的汇总的题目
- 关于分类汇总的使用
- 关于scanf的一点汇总
- 关于x++的题目汇总
- 关于UITextFiled的用法汇总
- 关于Data的问题汇总
- 关于HTML的基础知识汇总
- 一些排序算法的汇总
- 字符串逆序的算法汇总
- 常用的排序算法汇总
- 线段树题型汇总
- [转]线段树汇总
- boot.img和recovery.img结构说明
- java tips 之 java Time
- 静态方法调用dll函数及类
- 四十二、继承与派生:虚基类及其派生类的构造函数
- 实时显示iOS编写UI代码效果:有效提高UI编写速度
- 关于线段的算法汇总
- 软件架构设计书籍介绍
- IOS常用第三方框架 --- SVPullToRefresh 下拉刷新、上拉加载更多
- eCall - 简介
- 使用ideploy的安装
- linux GDB调试器的使用
- 关于HTML和CSS中左右布局中的浮动问题
- 关于linux下my.ini配置文件的加载顺序
- 按产品经理能力划分,我们需要看哪些书?