一道图的题

最近遇到的一道算法题:
有一个坐标系,输入一组数据input:, eg:

const input = [
    [0, 0],
    [1, 1],
    [3, 1],
    [1, 2],
    [3, 2],
    [2, 3],
    [1, 4],
    [2, 4],
    [4, 4],
    [4, 5],
    [3, 4]
];

input的每个值(数组)是一组坐标,对应到图是这样的,

输出为:

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

即要求相邻的坐标为一组,输出符合这种要求的所有的组。

一开始只看数据以为是模拟找数字相同的,后面对照着图看确定是一个图的题,这不就是以前大学图论里的求所有的连通分量嘛。。。还好以前大学搞过一段时间图论,有点基础和概念底子,不知道的一般前端现场看到这种题可能比较懵吧。。。

我的思路就是建立坐标系,把input的输入变为坐标系的1,其余0或者undefined,从input的每个坐标开始dfs,如果没搜过push进当前的group,然后朝四个方向继续dfs。这里有个细节就是注意要标志下是否搜索过,我当时使用map存了一下,如果push进过group,就存进map里,dfs进入的时候统一判断。后面下来想了下其实直接push完把当前坐标系的值重置为0就好了。下面是我当时通过样例的代码,当时还要求现场bug free,又费了会儿时间,感觉这种大题有思路还要现场bug free还是费点时间的。如果这道题如果只是在意考察思路,可以变成求连通分量的数量,少处理点坐标系相关的可以节省时间。

function solve(input) {
    let mpMax = 6;
    let ans = [];
    let mp = [];
    for (let i = 0; i < mpMax; i++) {
        mp[i] = [];
        for (let j = 0; j < mpMax; j++) {
            mp[i][j] = 0;
        }
    }
    input.forEach((item) => {
        mp[item[0]][item[1]] = 1;
    });
    let map = new Map();
    for (let k = 0; k < input.length; k++) {
        let item = input[k];
        let i = item[0];
        let j = item[1];
        if (map.has(i.toString() + j.toString())) continue;
        let ret = [];
        // ret.push(item);
        dfs(i, j, ret);
        ans.push(ret);
    }
    return ans;
    function dfs(i, j, ret) {
        // 边界条件
        if (i < 0 || i > mpMax || j < 0 || j > mpMax || mp[i][j] !== 1) {
            return;
        }
        if (map.has(i.toString() + j.toString())) return;
        console.log('mp[i][j]', i, j, mp[i][j]);
        if (mp[i][j]) {
            // ret.push(mp[i][j]);
            ret.push([i, j]);
            map.set(i.toString() + j.toString(), 1);
        }
        dfs(i, j + 1, ret);
        dfs(i, j - 1, ret);
        dfs(i + 1, j, ret);
        dfs(i - 1, j, ret);
    }
}
posted @ 2024-02-23 02:14  Lawliet__zmz  阅读(13)  评论(0编辑  收藏  举报