【问题标题】:Find all collinear of 3 points找到 3 个点的所有共线
【发布时间】:2019-11-07 13:59:13
【问题描述】:

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

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

我没有通过测试,但我还是自己完成了,找不到任何我能理解的解决方案。

这是数据集

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

数据集的图像

解决方案应该返回 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]])
    );

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

所以如果有人有任何建议,请告诉我。

【问题讨论】:

标签: javascript node.js algorithm


【解决方案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; }

【讨论】:

  • 蛮力是 n^3。我认为你不能比 n^2 更好地查看所有行。
  • 你有提示吗?
  • 是的,我的代码似乎仍然更有效率,因为它小于 n^2。但是谢谢你,因为我尝试了蛮力方法,它的效率比你的低。所以我认为我仍然可以从中学到一些东西。另外我是正确的,你计算的是 4 而不是 6?
猜你喜欢
  • 2020-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-07
  • 2016-12-11
  • 2014-05-22
  • 2021-11-17
  • 2018-03-14
相关资源
最近更新 更多