扫描线Sweep Line算法总结
扫描线算法,推荐还是用标准的模板去写,treemap只适合于求最大的overlap个数的题目,其余的不能用treemap来解,所以推荐还是用event的思想去+1, -1然后排序扫描的方法可以用来解所有的题型;
Number of Airplanes in the Sky 思路:经典扫描线算法:把interval起飞和降落做为event,全部打散,按照时间排列,同时时间相等的,按照降落在前面,起飞在后面进行排序;最后再扫一遍,遇见start,count++,遇见end,count--,然后最后中间出现的最大值,就是题目所求。
/*** Definition of Interval:* public classs Interval {* int start, end;* Interval(int start, int end) {* this.start = start;* this.end = end;* }* }*/public class Solution {/*** @param airplanes: An interval array* @return: Count of airplanes are in the sky.*/private class Node {public int time;public int flag;public Node(int time, int flag) {this.time = time;this.flag = flag;}}public int countOfAirplanes(List<Interval> airplanes) {int count = 0;List<Node> list = new ArrayList<Node>();for(Interval interval: airplanes) {list.add(new Node(interval.start, 1));list.add(new Node(interval.end, -1));}Collections.sort(list, (a, b) -> a.time != b.time ? a.time - b.time : a.flag - b.flag);int maxplane = 0;for(int i = 0; i < list.size(); i++) {Node node = list.get(i);if(node.flag == 1) {count++;} else {count--;}maxplane = Math.max(maxplane, count);}return maxplane;}
}
也可以用treemap来做, <Integer, Integer> 分别代表index和出现的次数 start +1, end -1, 然后for loop一下key,就是扫描,因为treemap的key是sorted;
/*** Definition of Interval:* public classs Interval {* int start, end;* Interval(int start, int end) {* this.start = start;* this.end = end;* }* }*/public class Solution {/*** @param airplanes: An interval array* @return: Count of airplanes are in the sky.*/public int countOfAirplanes(List<Interval> airplanes) {TreeMap<Integer, Integer> treemap = new TreeMap<>();for(Interval interval: airplanes) {treemap.put(interval.start, treemap.getOrDefault(interval.start, 0) + 1);treemap.put(interval.end, treemap.getOrDefault(interval.end, 0) - 1);}int maxcount = 0;int count = 0;for(Integer key: treemap.keySet()) {count += treemap.get(key);maxcount = Math.max(maxcount, count);}return maxcount;}
}
Meeting Rooms II 思路:题目跟上面飞机一模一样,代码都是一样的。
class Solution {private class Node {public int time;public int flag;public Node(int time, int flag) {this.time = time;this.flag = flag;}}public int minMeetingRooms(int[][] intervals) {if(intervals == null || intervals.length == 0) {return 0;} List<Node> list = new ArrayList<>();for(int[] interval: intervals) {list.add(new Node(interval[0], 1));list.add(new Node(interval[1], -1));}int count = 0;int maxcount = 0;Collections.sort(list, (a, b) -> (a.time != b.time ? a.time - b.time : a.flag - b.flag));for(Node node: list) {if(node.flag == 1) {count++;} else {count--;}maxcount = Math.max(maxcount, count);}return maxcount;}
}
也可以用treemap写,<Integer, Integer> 分别代表的是start 和出现的次数. start的时候,+1, end的时候,-1;然后过keyset,就是扫描一遍,求最大;
class Solution {public int minMeetingRooms(int[][] intervals) {TreeMap<Integer, Integer> treemap = new TreeMap<>();for(int[] interval: intervals) {treemap.put(interval[0], treemap.getOrDefault(interval[0], 0) + 1);treemap.put(interval[1], treemap.getOrDefault(interval[1], 0) - 1);}int maxcount = 0;int count = 0;for(Integer key: treemap.keySet()) {count += treemap.get(key);maxcount = Math.max(maxcount, count);}return maxcount;}
}
Time Intersection 思路:扫描线算法,注意的是,阈值发生变化的时候,收集数据,一定要在count = 2的时候收集。
/*** Definition of Interval:* public classs Interval {* int start, end;* Interval(int start, int end) {* this.start = start;* this.end = end;* }* }*/public class Solution {/*** @param seqA: the list of intervals* @param seqB: the list of intervals* @return: the time periods*/private class Node {public int time;public int flag;public Node(int time, int flag) {this.time = time;this.flag = flag;}}public List<Interval> timeIntersection(List<Interval> seqA, List<Interval> seqB) {List<Node> list = new ArrayList<>();List<Interval> result = new ArrayList<>();for(Interval interA: seqA) {list.add(new Node(interA.start, 1));list.add(new Node(interA.end, -1));}for(Interval interB: seqB) {list.add(new Node(interB.start, 1));list.add(new Node(interB.end, -1));}Collections.sort(list, (a, b) -> (a.time != b.time ? a.time - b.time : a.flag - b.flag));int count = 0;int start = -1; int end = -1;for(Node node: list) {if(node.flag == 1) {count++;if(count == 2) {start = node.time;}}if(node.flag == -1) {if(count == 2) {end = node.time;result.add(new Interval(start, end));start = -1;end = -1;}count--;}}return result;}
}
思路2:这题因为数据是sorted,因为A和B都是sorted,那么跟merge array一样,可以用打擂台的方式,每次踢走一个。
如果Max(startA, startB) < Min(endA, endB)则加入相交的interval 然后看A, B end 谁大,谁留下,另外一个踢走;O(N+M) 因为数据是sorted,那么就按照overlap来扫描,也就是start取最大值,end取最小值,如果start< end,表明有overlap,否则不会有overlap,同时end较小的扔掉,较大的留下;
/*** Definition of Interval:* public classs Interval {* int start, end;* Interval(int start, int end) {* this.start = start;* this.end = end;* }* }*/public class Solution {/*** @param seqA: the list of intervals* @param seqB: the list of intervals* @return: the time periods*/public List<Interval> timeIntersection(List<Interval> seqA, List<Interval> seqB) {List<Interval> result = new ArrayList<Interval>();if(seqA == null || seqA.size() == 0 || seqB == null || seqB.size() == 0) {return result;}int aIndex = 0;int bIndex = 0;// 因为数据是sorted,那么就按照overlap来扫描,也就是start取最大值,end取最小值,// 如果start< end,表明有overlap,否则不会有overlap,同时end较小的扔掉,较大的留下;while(aIndex < seqA.size() && bIndex < seqB.size()) {int start = Math.max(seqA.get(aIndex).start, seqB.get(bIndex).start);int end = Math.min(seqA.get(aIndex).end, seqB.get(bIndex).end);if(start < end) {result.add(new Interval(start, end));}if(seqA.get(aIndex).end < seqB.get(bIndex).end) {aIndex++;} else {bIndex++;}}return result;}
}
Meeting Scheduler: 跟上面一样,两个array按照start,排序之后,两个指针交替进行打擂台。T( mlogm + nlogn);
class Solution {public List<Integer> minAvailableDuration(int[][] slots1, int[][] slots2, int duration) {List<Integer> list = new ArrayList<Integer>();Arrays.sort(slots1, (a, b) -> (a[0] - b[0]));Arrays.sort(slots2, (a, b) -> (a[0] - b[0]));int a = 0; int b = 0;while(a < slots1.length && b < slots2.length) {// start 取最大,end 取最小;int start = Math.max(slots1[a][0], slots2[b][0]);int end = Math.min(slots1[a][1], slots2[b][1]);if(start < end && end - start >= duration) {list.add(start);list.add(start + duration);return list;} else {if(slots1[a][1] < slots2[b][1]) {a++;} else {b++;}}}return list;}
}
Skyline problem: 思路:扫描线算法;起飞的时候才加入一堆高度进行排序判断最高height,下降的时候,要remove 当前的高度,由于下降的点刚开始存的时候就是负数,所以remove的时候就是remove -负数。不参加评选了。还有注意点就是pq刚开始有可能是空的时候,curheight是0. 否则会报NPE;
class Solution {private class Node {public int x;public int height;public Node(int x, int height) {this.x = x;this.height = height;}}public List<List<Integer>> getSkyline(int[][] buildings) {List<List<Integer>> lists = new ArrayList<List<Integer>>();if(buildings == null || buildings.length == 0 || buildings[0].length == 0) {return lists;}List<Node> list = new ArrayList<>();for(int[] building: buildings) {list.add(new Node(building[0], building[2]));list.add(new Node(building[1], -building[2])); }// 找高度最大的;Collections.sort(list, (a, b) -> (a.x != b.x ? a.x - b.x : b.height - a.height));int preheight = 0;int curheight = 0;PriorityQueue<Integer> pq = new PriorityQueue<Integer>((a, b) -> (b - a));for(Node node: list) {if(node.height > 0) {//左边正数,加入pq进行排序;pq.offer(node.height);} else {// 因为存进去正负号是为了代表左边和右边,左边加入,右边remove,所以这里要remove -height;pq.remove(-node.height);}// 注意这里要判断pq是否为空,为空就是0,不为空才是peek;curheight = pq.isEmpty() ? 0 : pq.peek();if(curheight != preheight) {List<Integer> res = new ArrayList<>();res.add(node.x);res.add(curheight);lists.add(res);preheight = curheight;}}return lists;}
}
Employee Free Time 思路1:sort interval,然后每次判断last.end和next.start的距离,如果不相交,加入间隔进result,否则把last踢掉;用collections sort;
/*
// Definition for an Interval.
class Interval {public int start;public int end;public Interval() {}public Interval(int _start, int _end) {start = _start;end = _end;}
};
*/class Solution {public List<Interval> employeeFreeTime(List<List<Interval>> schedule) {List<Interval> list = new ArrayList<Interval>();for(List<Interval> intervals: schedule) {for(Interval interval: intervals) {list.add(interval);}}Collections.sort(list, (a, b) ->(a.start - b.start));Interval last = list.get(0);List<Interval> result = new ArrayList<Interval>();for(int i = 1; i < list.size(); i++) {Interval cur = list.get(i);if(last.end < cur.start) {result.add(new Interval(last.end, cur.start));last = cur;} else {// last.end >= cur.start;last.end = Math.max(last.end, cur.end);}}return result;}
}
思路2:sweep line,起点+1终点-1,count为0的时候,先find 起点,再find终点;NlogN
/*
// Definition for an Interval.
class Interval {public int start;public int end;public Interval() {}public Interval(int _start, int _end) {start = _start;end = _end;}
};
*/class Solution {private class Node {public int time;public int flag;public Node(int time, int flag) {this.time = time;this.flag = flag;}}public List<Interval> employeeFreeTime(List<List<Interval>> schedule) {List<Node> list = new ArrayList<Node>();for(List<Interval> templist : schedule) {for(Interval interval: templist) {list.add(new Node(interval.start, 1));list.add(new Node(interval.end, -1));}}Collections.sort(list, (a, b) -> (a.time != b.time ? a.time - b.time : a.flag - b.flag));int count = 0;Integer start = null;Integer end = null;List<Interval> result = new ArrayList<Interval>();for(Node node : list) {if(node.flag == 1) {count++;if(count == 1 && start != null) {end = node.time;if(end > start) {result.add(new Interval(start, end));}start = null;end = null;}} else {// node.flag == -1;count--;if(count == 0) {start = node.time;}}}return result;}
}
Brick Wall 思路: 扫描线算法,m * n log(m * n); 注意头跟尾的时候,不能update count,只能在中间;
class Solution {private class Node {public int index;public int flag;public Node(int index, int flag) {this.index = index;this.flag = flag;}}public int leastBricks(List<List<Integer>> walls) {if(walls == null || walls.size() == 0) {return 0;}List<Node> list = new ArrayList<Node>();int totallen = 0;for(List<Integer> wall: walls) {int len = 0;for(Integer w: wall) {list.add(new Node(len, 1));len += w;list.add(new Node(len, -1));}totallen = len;}int mincount = walls.size();Collections.sort(list, (a, b) -> (a.index != b.index ? a.index - b.index : a.flag - b.flag));int count = 0;for(Node node: list) {if(node.flag == 1) {count++;} if(node.flag == -1) {count--;}if(node.index != 0 && node.index != totallen) {mincount = Math.min(mincount, count);}}return mincount;}
}
思路:逆向思维,因为len都是正数,那么我们count 相同len的最多有多少个,那么答案就是rows - mostfre;
class Solution {public int leastBricks(List<List<Integer>> wall) {if(wall == null || wall.size() == 0) {return 0;}HashMap<Integer, Integer> countmap = new HashMap<Integer, Integer>();int mostfre = 0;for(List<Integer> list: wall) {int len = 0;for(int i = 0; i < list.size() - 1; i++) {len += list.get(i);countmap.put(len, countmap.getOrDefault(len, 0) + 1);mostfre = Math.max(mostfre, countmap.get(len));}}return wall.size() - mostfre;}
}
My Calendar I 思路:标准扫描线算法,比treemap慢点;每次都要nlogn的排序;
class MyCalendar {private class Node {public int index;public int flag;public Node(int index, int flag) {this.index = index;this.flag = flag;}}private List<Node> list;public MyCalendar() {list = new ArrayList<>();}public boolean book(int start, int end) {Node startNode = new Node(start, 1);Node endNode = new Node(end, -1);list.add(startNode);list.add(endNode);Collections.sort(list, (a, b) -> (a.index != b.index ? a.index - b.index : a.flag - b.flag));int count = 0;int maxcount = 0;for(Node node: list) {if(node.flag == 1) {count++;} else {count--;}maxcount = Math.max(maxcount, count);}if(maxcount == 2) {list.remove(startNode);list.remove(endNode);}return maxcount <= 1 ? true : false;}
}/*** Your MyCalendar object will be instantiated and called as such:* MyCalendar obj = new MyCalendar();* boolean param_1 = obj.book(start,end);*/
思路:用treemap去存所有之前的 (start, end) , key is start, end is value; 那么就按照start自然的进行sort,每次加入是logn的操作;然后treemap, 有floorKey 和ceilingKey的操作,分别也是logn, 判断一下 (floorkey, flookey_value) (start, end) (ceilingkey, ceilingkey_value)是否有重合;
class MyCalendar {TreeMap<Integer, Integer> treemap;public MyCalendar() {this.treemap = new TreeMap<>();}// (floorkey, floorvalue), (start, end), (ceilingkey, ceilingvalue);public boolean book(int start, int end) {Integer floorkey = treemap.floorKey(start);if(floorkey != null && treemap.get(floorkey) > start) {return false;}Integer ceilingkey = treemap.ceilingKey(start);if(ceilingkey != null && end > ceilingkey) {return false;}treemap.put(start, end);return true;}
}/*** Your MyCalendar object will be instantiated and called as such:* MyCalendar obj = new MyCalendar();* boolean param_1 = obj.book(start,end);*/
My Calendar II 思路:标准的扫描线,每次需要排序;但是performance,比treemap要快;
class MyCalendarTwo {private class Node {public int index;public int flag;public Node(int index, int flag) {this.index = index;this.flag = flag;}}private List<Node> list;public MyCalendarTwo() {list = new ArrayList<Node>();}public boolean book(int start, int end) {Node startNode = new Node(start, 1);Node endNode = new Node(end, -1);list.add(startNode);list.add(endNode);Collections.sort(list, (a, b) -> (a.index != b.index ? a.index - b.index : a.flag - b.flag));int count = 0;int maxcount = 0;for(Node node: list) {if(node.flag == 1) {count++;} else {count--;}maxcount = Math.max(maxcount, count);}if(maxcount >= 3) {list.remove(startNode);list.remove(endNode);}return maxcount <= 2 ? true : false;}
}/*** Your MyCalendarTwo object will be instantiated and called as such:* MyCalendarTwo obj = new MyCalendarTwo();* boolean param_1 = obj.book(start,end);*/
思路:扫描线,用treemap<Integer, Integer> ( key x坐标,value: 起飞降落的个数)来代替priorityqueue做,start + 1, end -1, Treemap,自动维护x坐标的从小到大。T: 加入是 lgn, 扫描是O(N);
class MyCalendarTwo {TreeMap<Integer, Integer> treeMap;public MyCalendarTwo() {treeMap = new TreeMap<Integer, Integer>();}public boolean book(int start, int end) {// add it;treeMap.put(start, treeMap.getOrDefault(start, 0) + 1);treeMap.put(end, treeMap.getOrDefault(end, 0) - 1);// check if sweep line count > 3 or not;int count = 0;for(Integer key: treeMap.keySet()) {count += treeMap.get(key);if(count >= 3) {treeMap.put(start, treeMap.getOrDefault(start, 0) - 1);treeMap.put(end, treeMap.getOrDefault(end, 0) + 1);return false;}}return true;}
}/*** Your MyCalendarTwo object will be instantiated and called as such:* MyCalendarTwo obj = new MyCalendarTwo();* boolean param_1 = obj.book(start,end);*/
My Calendar III 思路:还是建议用标准的 sweep line的代码写,比较标准化,可以解所有的题;
class MyCalendarThree {private class Node {public int index;public int flag;public Node(int index, int flag) {this.index = index;this.flag = flag;}}private List<Node> list;public MyCalendarThree() {list = new ArrayList<Node>();}public int book(int start, int end) {list.add(new Node(start, 1));list.add(new Node(end, -1));Collections.sort(list, (a, b) -> (a.index != b.index ? a.index - b.index : a.flag - b.flag));int count = 0;int maxcount = 0;for(Node node: list) {if(node.flag == 1) {count++;} else {count--;}maxcount = Math.max(maxcount, count);}return maxcount;}
}/*** Your MyCalendarThree object will be instantiated and called as such:* MyCalendarThree obj = new MyCalendarThree();* int param_1 = obj.book(start,end);*/
思路2:跟 My Calendar II 类似 ,求overlap的最大; 扫描线;求中间count的最大值;
class MyCalendarThree {TreeMap<Integer, Integer> treeMap;public MyCalendarThree() {treeMap = new TreeMap<Integer, Integer>();}public int book(int start, int end) {// add it;treeMap.put(start, treeMap.getOrDefault(start, 0) + 1);treeMap.put(end, treeMap.getOrDefault(end, 0) - 1);// check if sweep line count;int count = 0;int maxcount = 0;for(Integer key: treeMap.keySet()) {count += treeMap.get(key);maxcount = Math.max(maxcount, count);}return maxcount;}
}/*** Your MyCalendarThree object will be instantiated and called as such:* MyCalendarThree obj = new MyCalendarThree();* int param_1 = obj.book(start,end);*/
扫描线Sweep Line算法总结相关推荐
- d3设置line长度_万物皆可Embedding之LINE算法解读
需要论文的朋友可以后台私信我获取 前言 上一篇文章给大家带来了Graph Embedding技术中的代表算法Deepwalk,今天给大家介绍graph embedding又一代表算法--LINE,LI ...
- d3设置line长度_Graph Embedding之LINE算法解读
需要论文的朋友可以后台私信我获取 前言 上一篇文章给大家带来了Graph Embedding技术中的代表算法Deepwalk,今天给大家介绍graph embedding又一代表算法--LINE,LI ...
- 论文|LINE算法原理、代码实战和应用
1 概述 LINE是2015年微软发表的一篇论文,其全称为: Large-scale Information Network Embedding.论文下载地址:https://arxiv.org/pd ...
- 求解VRP问题的节约里程法、sweep扫描算法和λ互换法
第05章 求解容量约束车辆路径问题的启发式算法 Edited by Jiannywang@163.com 目 录 5.1 节约里程法. 1 5.1.1 C-W节约算法简介. 1 5.1.2 C-W ...
- 多边形区域填充算法--扫描线种子填充算法
分享一下我老师大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow http://bl ...
- 计算机图形学 ———— 扫描线多边形填充算法 (讲解)
一.基本原理 扫描线多边形区域填充算法是按扫描线顺序(由下到上),计算扫描线与多边形的相交区间,再用要求的颜色显示这些区间的象素,即完成填充工作. ...
- 扫描线填充多边形算法详解与代码
扫描线填充多边形算法详解与代码 首先给出已知信息:多边形结构体里面包含三个信息:顶点个数,顶点和颜色 class MyPolygon {public:int m_VerticeNumber;CPoin ...
- 【计算机图形学 】扫描线多边形填充算法 | OpenGL+鼠标交互
文章目录 其他计算机图形学实验 前言 思路借鉴 步骤 1.点的结构体 2. AET 活性边表.NET新边表 的结构体 3. 扫描线算法实现 4. 改变鼠标响应函数 完整代码 总结 其他计算机图形学实验 ...
- 泰森多边形(Voronoi diagram)
泰森多边形(Voronoi diagram) 荷兰气候学家A•H•Thiessen提出了一种根据离散分布的气象站的降雨量来计算平均降雨量的方法,即将所有相邻气象站连成三角形,作这些三角形 ...
最新文章
- 【解决方案】npm安装vue超时(ERR! errno ETIMEDOUT)
- Android Java 8使用Lamda报错:Execution failed for task :app:transformJackWithJackForDebug - Android?...
- gatewayproperties 是空_一个空手套白狼的商业模式
- php恶意代码,php快速查找数据库中恶意代码的方法,快速查找恶意代码_PHP教程...
- P4111 [HEOI2015]小Z的房间
- 街舞中的rolling机器人_首家!爆点!奈雪の茶、蛙小侠..开业倒计时!街舞PK…这个六一就差你来围观了...
- Tesla P100
- bash log传到日志服务器
- [JSP]自定义标签库taglib
- 数据库完整性概念和数据库安全性概念之间的区别与联系
- Linux添加磁盘和挂载
- 全球第二大硬盘磁头专业制造商成都建基地
- 什么方法可以显著提高程序员工作效率
- 一元线性回归(R语言)
- kali拿网站服务器,Kali攻破网站和服务器
- 让你彻底理解线性代数中的概念——《线性代数的本质》系列视频笔记
- 【工具】- 在线画图
- 03.mysql调优--索引基本实现
- 周浩正:写给编辑人的信:繁盛的秘诀之二
- GitChat · 软件工程 | 一小时教你学会 Maven 项目的构建与管理
热门文章
- Keras深度学习之分层概念
- 用C语言实现快速排序算法
- YGG 与领先的 Solana NFT 市场平台 Magic Eden 达成合作
- 必胜客联合创办人去世 享年82岁
- matlab元胞自动机入门详解
- SSL P1618 剑鱼行动
- 发红包小程序最终版(趣味)
- WinForm界面开发之布局控件“WeifenLuo.WinFormsUI.Docking“的使用
- 如何强制不使用科学计数法
- SwiftUI iOS 15 将如何改进可访问性accessibility WWDC2021