开启我的LeetCode刷题日记:587. 安装栅栏

191 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情

编程世界总是离不了算法

最近在看框架源码时,会有很多算法的实现逻辑,有时候会感到吃力

于是决定蹭着假期,加强算法和数据结构相关的知识

那怎么提升呢?

其实我知道算法这东西没有捷径,多写多练才能提升,于是我开启我的LeetCode刷题之旅

第一阶段目标是:200道,每天12

为了不乱,本系列文章目录分为三部分:

  1. 今日题目:xxx
  2. 我的思路
  3. 代码实现

今日题目:587. 安装栅栏

在一个二维的花园中,有一些用 (x, y) 坐标表示的树。由于安装费用十分昂贵,你的任务是先用最短的绳子围起所有的树。只有当所有的树都被绳子包围时,花园才能围好栅栏。你需要找到正好位于栅栏边界上的树的坐标。

 

示例 1:

输入: [[1,1],[2,2],[2,0],[2,4],[3,3],[4,2]] 输出: [[1,1],[2,0],[4,2],[3,3],[2,4]]

示例 2:

输入: [[1,2],[2,2],[4,2]]
输出: [[1,2],[2,2],[4,2]]

注意:

  1. 所有的树应当被围在一起。你不能剪断绳子来包围树或者把树分成一组以上。
  2. 输入的整数在 0 到 100 之间。
  3. 花园至少有一棵树。
  4. 所有树的坐标都是不同的。
  5. 输入的点没有顺序。输出顺序也没有要求。

来源:力扣(LeetCode) 链接:leetcode.cn/problems/er… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我的思路

1。先排序所有的点,按坐标x值排序,如果x值一样按y值排。

2。先正序遍历,计算下半部分的凸包。

3。再倒序遍历,计算上半部分的凸包

代码实现

/**
 * @param {number[][]} trees
 * @return {number[][]}
 */
var outerTrees = function(trees) {
    const n = trees.length;
    const map = {};
    for (let i = 0; i < n; i++) {
        const items = map[trees[i][0]] || [];
        items.push(trees[i][1]);
        map[trees[i][0]] = items;
    }
    const sortArray = [];
    for (const key in map) {
        const items = map[key];
        items.sort((a, b) => {
            return b - a;
        });
        sortArray.push([key, items]);
    }
    sortArray.sort((a, b) => {
        return a[0] - b[0];
    });
    const m = sortArray.length;
    let topX = sortArray[0][0]; let topY = sortArray[0][1][0]; let bottomX = topX; let bottomY = sortArray[0][1][sortArray[0][1].length-1]; 
    const res = [];

    const topSelector = (topPoint, i, x) => {
        const k1 = (topPoint - topY) / (x - topX);
        let selected = true;
        for (let a = i+1; a < m; a++) {
            const k2 = (sortArray[a][1][0] - topY) / (sortArray[a][0] - topX);
            if (k1 < k2) {
                selected = false;
                break;
            }
        }
        if (selected) {
            res.push([x, topPoint]);
            topX = x;
            topY = topPoint;
        }
        return selected;
    };

    const bottomSelector = (bottomPoint, i, x) => {
        const k1 = (bottomPoint - bottomY) / (x - bottomX);
        let selected = true;
        for (let a = i+1; a < m; a++) {
            const k2 = (sortArray[a][1][sortArray[a][1].length-1] - bottomY) / (sortArray[a][0] - bottomX);
            if (k1 > k2) {
                selected = false;
                break;
            }
        }
        if (selected) {
            res.push([x, bottomPoint]);
            bottomX = x;
            bottomY = bottomPoint;
        }
        return selected;
    };

    for (let i = 0; i < m; i++) {
        const x = sortArray[i][0];
        const yArray = sortArray[i][1];
        if (i === 0 || i === m-1) {
            for (let j = 0; j < yArray.length; j++) res.push([x, yArray[j]]);
        } else {
            let topPoint;
            let bottomPoint;
            if (yArray.length === 1) {
               if (Math.abs(yArray[0] - topY) <= Math.abs(yArray[0] - bottomY) && bottomY < yArray[0]) topPoint = yArray[0];
               else bottomPoint = yArray[0]; 
            } else {
                topPoint = yArray[0];
                bottomPoint = yArray[yArray.length-1];
            }
            if (topPoint !== undefined) {
                topSelector(topPoint, i , x);
            }
            if (bottomPoint !== undefined) {
                const flag = bottomSelector(bottomPoint, i , x);
                if (topPoint === undefined && !flag) topSelector(bottomPoint, i , x);
            }
        }
    }
    return res;
};

总结

实现方式其实有很多,这里仅供参考~

由于刚开始刷题,也不知道从哪里刷好,如果前辈们有好的建议,希望不吝赐教,感谢🌹