Leetcode:The Skyline Problem
题目大意:太复杂了,不太想翻译。对于一丛相互交错的方形建筑,可以由一个二维数组表示各自的轮廓。求从远处观望时看到的天际线。所谓的天际线就是某一段水平区域上的等高线,其下方或者是建筑,或者是地面。求从左到右的天际线序列,且相邻天际线高度不等(等高天际线合并)。需要输出的是每个天际线的左端点位置。
这道题可以通过对离散数据的压缩和线段树解答。
首先将所有端点的x坐标进行压缩(实际上就是对其进行排序和去重,之后用排序的下标代替原来值),映射为0~O(n)个连续整数,其中n为建筑的数目。之所以要压缩数据是为了让线段树使用尽可能少的空间。这里用f表示数据的对应关系,f(x)表示x在有序数组中的下标,f(-1)(i)表示有序数组下标i处的值,f和f(-1)是互逆函数。
之后建立自定义线段树,线段树中区间[x,x].v表示点x+0.5的高度。而[x,y].v=max([x,x].v, [x+1,x+1].v, ... , [y, y].v)。线段树还需要支持设置区间[x,y]的v的最小值的set操作和取v的最大值的get操作。通过值缓存和操作延迟的技术可以保证在O(log2(n))的时间复杂度内可以完成get和set操作。
接下来第一步就是在线段树中建立整个图。遍历所有的建筑[l, r, h],利用线段树的set操作设置区间[f(l), f(r)]的v的最小值为h。
之后遍历整个线段树,将所有有序的区间[x,x]转换为点(f(-1)(x), [x,x].v)加入到结果集合result中。
最后从结果集合result中移除等高相邻的天际线。这是result就是我们要返回的结果了。
说一下时间复杂度,压缩数据(排序和去重)和后期执行的O(n)次f映射和f(-1)映射,分别需要时间复杂度O(nlog2(n))、O(nlog2(n))、O(n)。因此构建映射关系和使用映射关系总共时间复杂度为O(nlog2(n))+O(nlog2(n))+O(n)=O(nlog2(n))。
而线段树部分,建立线段树的时间复杂度为O(n),O(n)次set和get操作需要的时间复杂度分别为O(nlog2(n))、O(nlog2(n)),因此线段树操作占用时间复杂度为O(nlog2(n))。
最后result移除等高相邻的天际线时间复杂度为O(n),因为只需要一次遍历。
综合上面的结论,总的时间复杂度为“建立和使用映射关系” + “线段树操作” + “result移除” = O(nlog2(n)) + O(nlog2(n)) + O(n) = O(nlog2(n))。
空间复杂度压缩数据时有序数组需要占用O(n)的空间复杂度,线段树O(n)的空间复杂度,result同样也是O(n)的空间复杂度,故总空间复杂度为O(n)+O(n)+O(n)=O(n)。
下面给出代码:
1 class Solution { 2 public List<int[]> getSkyline(int[][] buildings) { 3 if (buildings.length == 0) { 4 return new ArrayList<>(); 5 } 6 7 CompressMap map = new CompressMap(buildings); 8 SegmenetTree tree = new SegmenetTree(0, map.size() - 1); 9 10 //Find all joint 11 for (int i = 0, bound = buildings.length; i < bound; i++) { 12 tree.setMin(map.get(buildings[i][0]), map.get(buildings[i][1] - 1), buildings[i][2]); 13 } 14 tree.toString(); 15 List<int[]> joints = new ArrayList<>(buildings.length); 16 17 for (int i = tree.getLeftBound() + 1, bound = tree.getRightBound(); i <= bound; i++) { 18 int height = tree.getMax(i, i); 19 int[] joint = new int[]{map.reverse(i), height}; 20 joints.add(joint); 21 } 22 23 List<int[]> result = new ArrayList<>(buildings.length); 24 result.add(joints.get(0)); 25 int lastHeight = joints.get(0)[1]; 26 for (int i = 1, bound = joints.size(); i < bound; i++) { 27 int[] joint = joints.get(i); 28 if (joint[1] == lastHeight) { 29 continue; 30 } 31 lastHeight = joint[1]; 32 result.add(joint); 33 } 34 35 //result.add(new int[]{map.get(tree.getRightBound()), 0}); 36 return result; 37 } 38 39 private static class CompressMap { 40 int[] orderedValues; 41 int length; 42 43 public CompressMap(int[][] buildings) { 44 orderedValues = new int[buildings.length * 4]; 45 for (int i = 0, bound = buildings.length; i < bound; i++) { 46 orderedValues[i << 2] = buildings[i][0]; 47 orderedValues[(i << 2) | 1] = buildings[i][1]; 48 orderedValues[(i << 2) | 2] = buildings[i][0] - 1; 49 orderedValues[(i << 2) | 3] = buildings[i][1] - 1; 50 } 51 52 Arrays.sort(orderedValues); 53 length = 1; 54 for (int i = 1, bound = orderedValues.length; i < bound; i++) { 55 if (orderedValues[i] != orderedValues[i - 1]) { 56 orderedValues[length++] = orderedValues[i]; 57 } 58 } 59 } 60 61 public int get(int val) { 62 return Arrays.binarySearch(orderedValues, 0, length, val); 63 } 64 65 public int reverse(int index) { 66 return orderedValues[index]; 67 } 68 69 public int size() { 70 return length; 71 } 72 } 73 74 private static class SegmenetTree { 75 int left; 76 int right; 77 int[] cacheValues; 78 int[] opMarks; 79 80 public SegmenetTree(int left, int right) { 81 this.left = left; 82 this.right = right; 83 84 int proper = 1; 85 int length = right - left + 1; 86 while (proper < length) { 87 proper <<= 1; 88 } 89 90 cacheValues = new int[proper * 2]; 91 opMarks = new int[proper * 2]; 92 } 93 94 public int getLeftBound() { 95 return left; 96 } 97 98 public int getRightBound() { 99 return right; 100 } 101 102 public void setMin(int from, int to, int val) { 103 setMin(from, to, left, right, 1, val); 104 } 105 106 private void setMin(int from, int to, int curLeft, int curRight, int index, int val) { 107 if (from > curRight || to < curLeft) { 108 return; 109 } 110 111 if (from <= curLeft && to >= curRight) { 112 cacheValues[index] = Math.max(cacheValues[index], val); 113 opMarks[index] = Math.max(opMarks[index], val); 114 return; 115 } 116 117 int mid = (curLeft + curRight) >> 1; 118 setMin(from, to, curLeft, mid, leftIndex(index), val); 119 setMin(from, to, mid + 1, curRight, rightIndex(index), val); 120 cacheValues[index] = Math.max(Math.max(cacheValues[leftIndex(index)], cacheValues[rightIndex(index)]), opMarks[index]); 121 } 122 123 public int getMax(int from, int to) { 124 return getMax(from, to, left, right, 1); 125 } 126 127 private int getMax(int from, int to, int curLeft, int curRight, int index) { 128 if (from <= curLeft && to >= curRight) { 129 return cacheValues[index]; 130 } 131 132 if (from > curRight || to < curLeft) { 133 return 0; 134 } 135 136 int mid = (curLeft + curRight) >> 1; 137 return Math.max(Math.max( 138 getMax(from, to, curLeft, mid, leftIndex(index)), 139 getMax(from, to, mid + 1, curRight, rightIndex(index)) 140 ), opMarks[index]); 141 } 142 143 public int leftIndex(int i) { 144 return (i << 1); 145 } 146 147 public int rightIndex(int i) { 148 return (i << 1) | 1; 149 } 150 151 @Override 152 public String toString() { 153 StringBuilder builder = new StringBuilder(); 154 for (int i = getLeftBound(); i < getRightBound(); i++) { 155 builder.append(getMax(i, i)).append(","); 156 } 157 if (builder.length() > 0) { 158 builder.setLength(builder.length() - 1); 159 } 160 return builder.toString(); 161 } 162 } 163 }
View Code
转载于:https://www.cnblogs.com/dalt/p/7758179.html
Leetcode:The Skyline Problem相关推荐
- LeetCode——218. 天际线问题(The Skyline Problem)[困难]——分析及代码(Java)
LeetCode--218. 天际线问题[The Skyline Problem][困难]--分析及代码[Java] 一.题目 二.分析及代码 1. 扫描线 + 优先队列 (1)思路 (2)代码 (3 ...
- [LeetCode-JAVA] The Skyline Problem
题目:题目太长了,见链接-- > The Skyline Problem Notes: The number of buildings in any input list is guarante ...
- LeetCode 218. The Skyline Problem
题目地址: 注意:做这道题前建议先做这道题Rectangle Area II - LeetCode 看这篇博客:LeetCode 850. Rectangle Area II A city's sky ...
- leetcode 218. The Skyline Problem | 218. 天际线问题(线段树)
题目 https://leetcode-cn.com/problems/the-skyline-problem/ 题解 线段树问题,根据左神的思路改编,外加我想到的压缩的 tricks(数字范围太大, ...
- [Swift]LeetCode218. 天际线问题 | The Skyline Problem
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblog ...
- Leetcode重点250题
LeetCode重点250题 这个重点题目是把LeetCode前400题进行精简.精简方法如下: 删除不常考,面试低频出现题目 删除重复代码题目(例:链表反转206题,代码在234题出现过) 删除过于 ...
- LeetCode github集合,附CMU大神整理笔记
Github LeetCode集合 本人所有做过的题目都写在一个java项目中,同步到github中了,算是见证自己的进步.github目前同步的题目是2020-09-17日之后写的题.之前写过的题会 ...
- LeetCode 从零单刷个人笔记整理(持续更新)
更新至2020.2.23 github:https://github.com/ChopinXBP/LeetCode-Babel 本人博客用于个人对知识点的记录和巩固. 用几乎所有可行的方法进行了实现和 ...
- leetcode top interview题目补充
这个列表中有78道题目,是leetcode上top interview questions中的.原本是有145道题目,但是部分题目和top 100 liked questions是重复的(见另一篇文章 ...
最新文章
- 十个jQuery图片画廊插件推荐
- “AI下乡”:华为和袁隆平一起种海水稻,欲改造1亿亩良田
- 为什么在 Verilog HDL 设计中一定要用同步而不能用异步时序逻辑?
- 台湾国立大学郭彦甫Matlab教程笔记(9) basic plotting
- 小甲鱼c++学习视频之运算符重载
- Object o = new Object()在内存中占几个字节
- linux网路编程之多线程并发服务器
- mongodb报错 An error occurred while loading navigation: topology was destroyed
- ArcGIS Server 10 Java 版的Rest服务的部署方法
- matplotlib创建图的基本方法
- eclipse优化方案
- MOSFET与三极管
- html网页实现查询功能实现,CSS与媒体查询实现网页导航功能(附代码)
- 自行车码表使用说明—SIGMA(西格玛) BC906
- 众恒微拓科技:品质退款率怎么优化
- 使用Echars实现水滴状、环形图、分割图、堆叠、组织架构图、地图轮廓等图表
- 学习笔记(97):R语言入门基础-pairs绘图
- OpenVpnCentos8部署
- 报错Failure executing javac, but could not parse the error原因分析
- GNSS连续运行单参考站解决方案