最初想到的办法其实很暴力,遍历一遍输入,用数组记录每个x上的最高高度。但这么做在输入唯独跨度较大的时候可能不适用,而且空间消耗太大。 看了下网上的二分解法,仅记录端点也可行。
由于输入是有序的(其实无序也可以),每次将输入平分为两部分,分别求得这两部分的端点后再merge即可。 二分的最终情况即仅有一个输入,此时返回这个输入矩形的左上端点和右下端点即可。
merge是比较重要的。对于两个端点list,merge之后的各个端点的x坐标肯定在这两个list当中,对应的高度应该是两个list在这个x上的最高高度。我们不妨用h1和h2分别记录两个list在各个x上的高度。遍历两个list,每次取出当前的最左端点和当前高度,与另一个list的当前高度比较确定这个端点的最终高度,若返回即和此时为空或者上一个端点的高度不同于这个高度,说明这的确是一个新的端点,可以加入结果集合。
public class Solution {
public List<int[]> getSkyline(int[][] buildings) {
if (buildings.length == 0)
{
return new LinkedList<int[]>();
}
return fun(buildings, 0, buildings.length - 1);
}
public LinkedList<int[]> fun(int[][] buildings,int st,int ed)
{
if (st < ed) {
int mid = st + (ed - st) / 2;
return merge(fun(buildings, st, mid),fun(buildings, mid + 1, ed));
} else {
LinkedList<int[]> rs = new LinkedList<int[]>();
rs.add(new int[] { buildings[st][0], buildings[st][2] });
rs.add(new int[] { buildings[st][1], 0 });
return rs;
}
}
private LinkedList<int[]> merge(LinkedList<int[]> l1, LinkedList<int[]> l2)
{
LinkedList<int[]> rs = new LinkedList<int[]>();
int h1 = 0, h2 = 0;
while (l1.size() > 0 && l2.size() > 0)
{
int x=0,h=0;
if( l1.getFirst()[0]<l2.getFirst()[0] )
{
x=l1.getFirst()[0];
h1=l1.getFirst()[1];
h=Math.max(h1,h2);
l1.removeFirst();
}
else if( l1.getFirst()[0]>l2.getFirst()[0] )
{
x=l2.getFirst()[0];
h2=l2.getFirst()[1];
h=Math.max(h1,h2);
l2.removeFirst();
}
else
{
x=l2.getFirst()[0];
h1=l1.getFirst()[1];
h2=l2.getFirst()[1];
h=Math.max(h1,h2);
l1.removeFirst();
l2.removeFirst();
}
if( rs.size()==0 || h!=rs.getLast()[1] )
{
rs.add(new int[] { x, h });
}
}
rs.addAll(l1);
rs.addAll(l2);
return rs;
}
}