javascript - 找到 3 个点的所有共线

标签 javascript node.js algorithm

我进行了一次工作面试测试,问题是找到数据集中 3 个点的所有共线数据点。

wolframalpha.com/input/?i=collinear+lines

我没有通过测试,但仍然自己完成了它,并且找不到任何我能理解的解决方案。

这是数据集

[[0, 0], [1, 1], [2, 2], [3, 3], [3, 2], [4, 2], [5, 1]]

数据集图像 enter image description here

解决方案应该返回 6 它的作用,但我只是想知道我是否得到了最佳解决方案。

我的解决方案:

    /**
     * Will return the amount of lines of 3 points or can made with 3 unique points
     * @param {number} dotsInLine
     *
     *  @returns {number} of lines of 3 points found
     */
    function countLineOf3(dotsInLine) {
        if (dotsInLine === 3) return 1;
        if (dotsInLine > 3) return (dotsInLine - 3) * dotsInLine;
        return 0;
    }

    /**
     * will go trough the array of found points on 1 axes and return the count of 3 point lines found
     * @param {array} foundInArr
     * @param {object} matrix
     *
     * @returns {number}
     */
    function foundInAddToCount(foundInArr, matrix) {
        let count = 0;
        for (let i = 0; i < foundInArr.length; i++) {
            count += countLineOf3(matrix[foundInArr[i]]);
        }

        return count;
    }

    function solution(A) {
        let count = 0;
        let maxX = 0;
        let maxY = 0;
        const xStrait = {};
        const xStraitFound = [];
        const yStrait = {};
        const yStraitFound = [];

        const lineUp = {};
        const lineUpFound = [];
        const lineDown = {};
        const lineDownFound = [];

        for (let i = 0; i < A.length; i++) {
            if (maxX < A[i][0]) maxX = A[i][0];
            if (maxY < A[i][1]) maxY = A[i][1];

            // find strait vertical points
            if (!xStrait[A[i][0]]) xStrait[A[i][0]] = 0;
            xStrait[A[i][0]]++;
            if (xStrait[A[i][0]] === 3) xStraitFound.push(A[i][0]);
            // find strait horizontal points
            if (!yStrait[A[i][1]]) yStrait[A[i][1]] = 0;
            yStrait[A[i][1]]++;
            if (yStrait[A[i][1]] === 3) yStraitFound.push(A[i][1]);

            // find points bottom left to top right
            const x = A[i][0];
            const y = A[i][1];

            const xMinY = x - y;
            const yMinx = y - x;
            //middle line
            let key;
            if (xMinY >= 0 && yMinx >= 0) {
                key = `${xMinY}${yMinx}`;
            } else if (xMinY >= 0 && yMinx < 0) {
                // y zero UP
                key = `${xMinY}0`;
            } else if (xMinY < 0 && yMinx >= 0) {
                // x zero UP
                key = `0${yMinx}`;
            }

            if (key) {
                if (!lineUp[key]) lineUp[key] = 0;
                lineUp[key]++;
                if (lineUp[key] === 3) lineUpFound.push(key);
            }

            const xPlusY = x + y;
            //find points top left to bottom right
            if (!lineDown[`0${xPlusY}`]) lineDown[`0${xPlusY}`] = 0;
            lineDown[`0${xPlusY}`]++;
            if (lineDown[`0${xPlusY}`] === 3) {
                lineDownFound.push(`0${xPlusY}`);
            }
        }

        count += foundInAddToCount(xStraitFound, xStrait);
        count += foundInAddToCount(yStraitFound, yStrait);

        count += foundInAddToCount(lineUpFound, lineUp);
        count += foundInAddToCount(lineDownFound, lineDown);
        return count;
    }

    console.log(
        solution([[0, 0], [1, 1], [2, 2], [3, 3], [3, 2], [4, 2], [5, 1]])
    );

我基本上对所有水平线、垂直线和交叉线进行排序(抱歉我找不到正确的英文单词),然后对它们进行计数并将它们相加。

因此,如果有人有任何提示,请告诉我。

最佳答案

您可以采用强力方法收集点对及其斜率/截距。

然后获取收集到的集合的最大大小。

这种方法是二次的。

function getAB([x1, y1], [x2, y2]) { // slope/intercept of y = ax + b
    var a;
    return x1 === x2
        ? [Infinity, x1]
        : [a = (y2 - y1) / (x2 - x1), y1 - a * x1];
}

var points = [[0, 0], [1, 1], [2, 2], [3, 3], [3, 2], [4, 2], [5, 1]],
    collection = {},
    usedPoints = new Set;

points.forEach((p1, i, a) => {
    if (usedPoints.has(p1.toString())) return;
    a.slice(i + 1).forEach((p2, j, b) => {
        if (usedPoints.has(p2.toString())) return;
        var key = JSON.stringify(getAB(p1, p2));
        collection[key] = collection[key] || new Set;
        collection[key].add(p1);
        collection[key].add(p2);
        usedPoints.add(p1.toString());
    });
});

console.log(Math.max(...Object.values(collection).map(s => s.size)));

console.log(Object.entries(collection).map(([k, v]) => [k, [...v].map(w => w.join(' '))]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

关于javascript - 找到 3 个点的所有共线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58750359/

相关文章:

node.js - 升级到 Gradle 7.3 后 Node 构建失败

php - 术语突出显示算法 (HTML)

javascript - 使用 phantomjs 将网页渲染为 pdf 时,如何自动调整 viewportSize 以占用整个页面宽度?

php - 在同一台机器上运行 Node.js 应用程序和 PHP

javascript - 类型错误 : Converting circular structure to JSON

javascript - 如何从我的 Ajax 调用 json 响应中更新 HTML 中的表数据?

algorithm - MATLAB 中超大矩阵的高效乘法

java - 从给定的数组构造一棵树

javascript - 将文件拖放到 Chrome 的 textarea 中时获取光标位置

javascript - 我应该在 useEffect 钩子(Hook)中使用 IIFE 吗?