https://leetcode.com/problems/the-skyline-problem/
A city’s skyline is the outer contour of the silhouette formed by all the buildings in that city when viewed from a distance. Now suppose you are given the locations and height of all the buildings as shown on a cityscape photo (Figure A), write a program to output the skyline formed by these buildings collectively (Figure B).


The geometric information of each building is represented by a triplet of integers [Li, Ri, Hi]
, where Li
and Ri
are the x coordinates of the left and right edge of the ith building, respectively, and Hi
is its height. It is guaranteed that 0 ≤ Li, Ri ≤ INT_MAX
, 0 < Hi ≤ INT_MAX
, and Ri - Li > 0
. You may assume all buildings are perfect rectangles grounded on an absolutely flat surface at height 0.
For instance, the dimensions of all buildings in Figure A are recorded as: [ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ]
.
The output is a list of “key points” (red dots in Figure B) in the format of [ [x1,y1], [x2, y2], [x3, y3], ... ]
that uniquely defines a skyline. A key point is the left endpoint of a horizontal line segment. Note that the last key point, where the rightmost building ends, is merely used to mark the termination of the skyline, and always has zero height. Also, the ground in between any two adjacent buildings should be considered part of the skyline contour.
For instance, the skyline in Figure B should be represented as:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ]
.
Solution. I finally understood this problem. The basic idea is that for each column, we should dissemble it into [left, height], [right, -height] and sort by x axis. After we have these points, we loop each point. As long as we see if the max height is changed, we add this point in the result list.
First of all, we have input [l1, r1, h1], [l2, r2, l2], etc. We transform it to [l1, h1], [r1, -h1], [l2, h1], [r2, -h2], etc.
For example, the input is [2 9 10], [3 7 15], [5 12 12]
Then we have transformation points[] = [2, 10], [9, -10], [3, 15], [7, -15], [5, 12], [5, -12]
Then we sort it according to x axis, we have: points[] = [2, 10], [3, 15], [5, 12], [7, -15], [9, 10], [12, -12]
Ok, after we got this, let’s start our cool algorithm. The idea is to use TreeMap. Key is height, value is the number of this height. We loop all the point in points[], if height(point[1]) is greater than 0, we increase the count of this height.
If height is less than 0, we decrease count of this height. If count is zero, we remove it.
After this process, we check to see if the maxHeight in TreeMap(which is lastKey() has changed. If it changed, we add this point to result.
An exception is this case: [0, 2, 3], [2, 5, 3].

Points will be [0, 3], [2, -3], [2, 3], [5, 0]. In this way, it will
have result: [0, 3], [2, 0], [2, 3], [5, 0]. But we should actually have result [0, 3], [5, 0]
Instead, we should sort like [0, 3], [2, 3], [2, -3], [5, 0]. In this way, it will output result [0, 3], [5, 0]
public static List<int[]> getSkyline(int[][] buildings) {
// 1. Build point elements
List<int[]> points = new ArrayList<>();
for (int[] build : buildings) {
points.add(new int[]{build[0], build[2]});
points.add(new int[]{build[1], -build[2]});
}
/** 2. sort the points according to x axis.
If the input is [0, 2, 3], [2, 5, 3]. Then points will be [0, 3], [2, -3], [2, 3], [5, 0]. In this way, it will
have result: [0, 3], [2, 0], [2, 3], [5, 0]
Instead, we should sort like [0, 3], [2, 3], [2, -3], [5, 0]. In this way, it will output result [0, 3], [5, 0]
**/
points.sort((p1, p2) -> p1[0] == p2[0] ? p2[1] - p1[1] : p1[0] - p2[0]);
// 3. Go through points and find the key point, using TreeMap and maxValue
int max = 0;
TreeMap<Integer, Integer> tm = new TreeMap<>(); // (key = Height, value = count)
tm.put(0, 1);
List<int[]> ans = new ArrayList<>();
for (int[] point : points) {
int height = point[1];
int count = tm.getOrDefault(Math.abs(height), 0);
if (height > 0) {
tm.put(height, count + 1);
}
else if (count == 1){
tm.remove(-height);
}
else {
tm.put(-height, count - 1);
}
int newMax = tm.lastKey();
if (max != newMax) {
ans.add(new int[]{point[0], newMax});
max = newMax;
}
}
return ans;
}
Check my code on github.