「前端刷题」218.天际线问题(HARD)

99 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情

题目(The Skyline Problem)

链接:leetcode-cn.com/problems/th… 解决数:371 通过率:55% 标签:树状数组 线段树 数组 分治 有序集合 扫描线 堆(优先队列) 相关公司:google microsoft amazon 城市的 天际线 是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度,请返回 由这些建筑物形成的 天际线 。

每个建筑物的几何信息由数组 buildings 表示,其中三元组 buildings[i] = [lefti, righti, heighti] 表示:

lefti 是第 i 座建筑物左边缘的 x 坐标。 righti 是第 i 座建筑物右边缘的 x 坐标。 heighti 是第 i 座建筑物的高度。 你可以假设所有的建筑都是完美的长方形,在高度为 0 的绝对平坦的表面上。

天际线 应该表示为由 “关键点” 组成的列表,格式 [[x1,y1],[x2,y2],...] ,并按 x 坐标 进行 排序 。关键点是水平线段的左端点。列表中最后一个点是最右侧建筑物的终点,y 坐标始终为 0 ,仅用于标记天际线的终点。此外,任何两个相邻建筑物之间的地面都应被视为天际线轮廓的一部分。

注意:输出天际线中不得有连续的相同高度的水平线。例如 [...[2 3], [4 5], [7 5], [11 5], [12 7]...] 是不正确的答案;三条高度为 5 的线应该在最终输出中合并为一个:[...[2 3], [4 5], [12 7], ...]

示例 1:

输入:buildings = [[2,9,10],[3,7,15],[5,12,12],[15,20,10],[19,24,8]] 输出:[[2,10],[3,15],[7,12],[12,0],[15,10],[20,8],[24,0]] 解释: 图 A 显示输入的所有建筑物的位置和高度, 图 B 显示由这些建筑物形成的天际线。图 B 中的红点表示输出列表中的关键点。 示例 2:

输入:buildings = [[0,2,3],[2,5,3]] 输出:[[0,3],[5,0]]

提示:

1 <= buildings.length <= 104 0 <= lefti < righti <= 231 - 1 1 <= heighti <= 231 - 1 buildings 按 lefti 非递减排序

思路

直接看呆萌

/**
 * @param {number[][]} buildings
 * @return {number[][]}
 */
var getSkyline = function (buildings) {
    const arr = [], ans = [], n = buildings.length;
    // 记录点,用负数标记右点
    for (let [l, r, h] of buildings) arr.push([l, h], [r, -h]);
    // 在x轴排序,x相同按y大的排
    arr.sort((a, b) => a[0] - b[0] || b[1] - a[1]);
    const m = arr.length, heights = [0];
    // 记录前一个最高高度
    // 用于过滤出在x点最高的点
    // 和过滤两点在x处有相同高度的情况
    let preH = 0;
    for (let [l, h] of arr) {
        // 通过二分插入该左点高度
        if (h > 0) heights.splice(search(heights, h), 0, h);
        // 通过二分移除右点高度
        else heights.splice(search(heights, -h), 1);
        // 前高度和当前最高高度不相等,说明出现了关键点
        if (preH !== heights[0]) {
            ans.push([l, heights[0]])
            preH = heights[0];
        }
    }
    return ans;
};

// 二分
function search(arr, tar) {
    let l = 0, r = arr.length - 1;
    while (l < r) {
        const mid = l + ((r - l) >> 1);
        if (arr[mid] === tar) return mid;
        else if (arr[mid] < tar) r = mid;
        else l = mid + 1;
    }
    return l;
}