leetcode: The Skyline Problem

本文介绍了一种高效求解天际线问题的算法。通过二分法将输入建筑物列表分割并递归处理,最终合并结果得到完整的天际线轮廓。算法关键在于合并过程中选取有效端点,确保轮廓准确且简洁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最初想到的办法其实很暴力,遍历一遍输入,用数组记录每个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;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值