【JavaScript版数据结构与算法面向大厂面试】第九章 数据结构之“图”

第九章 数据结构之“图”

9.1 图简介

在这里插入图片描述
一条边最多能连接两个节点。
在这里插入图片描述
也可以用链表来构建图。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.2 图的深度与广度优先遍历

在这里插入图片描述
在这里插入图片描述
在tu.js文件里面新建一个图:

// 利用objct和Array构建一个图 
var tu = {
    
    
    0: [1, 2],
    1: [2],
    2: [0, 3],
    3: [3]
}
module.exports = tu;

对图进行深度优先遍历:

var tu = require("./tu");//1、引入构造图的JS文件
var visited = new Set();//4、新建一个空字典,用来存放已经访问过的节点
var dfs = (n) => {
    
    //2、声明一个箭头函数,把要访问的节点传进去
    console.log(n);//3、访问当前节点
    visited.add(n);//5、把已经访问过的节点,放到字典中,方便以后不再访问
    tu[n].forEach(c => {
    
    //6、访问当前节点的相邻节点,但要排除已经访问过的节点
        if (!visited.has(c)) {
    
    //7、排除已经访问过的节点,之前访问过的节点就不再访问了
            dfs(c);//8、递归调用它自己,重复之前的操作
        }

    });
}
dfs(2);//9、从2节点开始,2相当于根节点

在这里插入图片描述
在tu.js文件里面新建一个图:

// 利用objct和Array构建一个图 
var tu = {
    
    
    0: [1, 2],
    1: [2],
    2: [0, 3],
    3: [3]
}
module.exports = tu;

对图进行广度优先遍历:

var tu = require("./tu");//1、引入构造图的JS文件

var visited = new Set();//3、新建一个空字典,用来存放已经访问过的节点
var queue = [2];//2、把根节点入队
visited.add(2);//4、把根节点添加到字典中,表示已经访问过了
while (queue.length) {
    
    //5、在队列在值的情况下进行当前元素的出队并访问操作
    var n = queue.shift(n);//6、在队头出队
    console.log(n);//7、访问当前元素
    tu[n].forEach(c => {
    
    //8、访问当前节点的相邻节点,但要排除已经访问过的节点
        if (!visited.has(c)) {
    
    //9、排除已经访问过的节点,之前访问过的节点就不再访问了
            queue.push(c);//10、没有访问过的节点入队
            visited.add(c);//11、把入队的节点添加到字典中,表示已经访问过了
        }
    });

}

9.3 LeetCode: 65. 有效数字

在这里插入图片描述
在这里插入图片描述
代码实现:

//有效数字
var isNumber = function (s) {
    
    
    var graph = {
    
    
        0: {
    
     'blank': 0, 'sign': 1, '.': 2, 'digit': 6 },
        1: {
    
     'digit': 6, '.': 2 },
        2: {
    
     'digit': 3 },
        3: {
    
     'digit': 3, 'e': 4 },
        4: {
    
     'digit': 5, 'sign': 7 },
        5: {
    
     'digit': 5 },
        6: {
    
     'digit': 6, '.': 3, 'e': 4 },
        7: {
    
     'digit': 5 }
    };
    let state = 0;
    for (c of s.trim()) {
    
    
        if (c >= '0' && c <= '9') {
    
    
            c = 'digit';
        } else if (c === ' ') {
    
    
            c = 'blank';
        } else if (c === '+'||c==='-') {
    
    
            c = 'sign';
        }
        state = graph[state][c];
        if(state===undefined){
    
    
            return false;
        }
    }
    if(state==3||state===5||state===6){
    
    
        return true;
    }
    return false;
};

代码解读:
构建一个图:
在这里插入图片描述
反把相应的字符对应相应的操作:
在这里插入图片描述

9.4 LeetCode: 417. 太平洋大西洋水流问题

在这里插入图片描述
在这里插入图片描述

代码实现:

// 太平洋
var pacificAtlantic = function (matrix) {
    
    
    if (!matrix || !matrix[0]) {
    
     return []; }
    const m = matrix.lenth;
    const n = matrix[0].lenth;
    const flow1 = Array.from({
    
     length: m }, () => new Array(n).fill(false));
    const flow2 = Array.from({
    
     length: m }, () => new Array(n).fill(false));

    const dfs = (r, c, flow) => {
    
    
        flow[r][c] = true;
        [[r - 1, c], [r + 1, c], [r, c - 1], [r, c + 1]].forEach(([nr, nc]) => {
    
    
            if (
                // 保证在矩阵中
                nr >= 0 && nr < m &&
                nc >= 0 && nc < n &&
                // 防止死循环
                !flow[nr][nc] &&
                // 保证逆流而上
                matrix[nr][nc] >= matrix[r][c]
            ) {
    
    
                dfs(nr, nc, flow);
            }
        });
    };
    // 沿着海岸线逆流而上
    for (let r = 0; r < m; r += 1){
    
    
        dfs(r, 0, flow1);
        dfs(r, n-1, flow2);
    }
    for (let c = 0; c < n; c += 1){
    
    
        dfs(0, c, flow1);
        dfs(m-1, c, flow2);
    }
    // 收集能流到两个大洋里的坐标
    const res = [];
    for (let r = 0; r <m;r+=1){
    
    
        for(let c = 0; c <n;c+=1){
    
    
            if(flow1[r][c]&&flow2[r][c]){
    
    
                res.push([r,c]);
            }
        }
    }
    return res;

};

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码解读:
排除矩阵为空或传进来的是一维数组的情况:
在这里插入图片描述
构建两个自己的矩阵:
在这里插入图片描述
得到矩阵的行数和列数:
在这里插入图片描述

9.5 LeetCode: 133. 克隆图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
法一:使用深度优先遍历做。
代码实现:

var cloneGraph=function(node){
    
    
    if(!node) return;
    const visited = new Map();
    visited.set(node,new Node(node.val));
    const q=[node];
    while(q.length){
    
    
        const n=q.shift();
        (n.neighbors||[]).forEach(ne => {
    
    
            if(!visited.has(ne)){
    
    
                q.push(ne);
                visited.set(ne,new Node(ne.val));
            }
            visited.get(n).neighbors.push(visited.get(ne));
        });
    }
    return visited.get(node);
};

在这里插入图片描述
代码解读:
深度优先遍历图:
在这里插入图片描述
复制每个节点,但还没有建立关系:
在这里插入图片描述
建立原生节点和复制后节点的映射关系,但还没有建立边。
在这里插入图片描述
建立边:
在这里插入图片描述
法二:使用广度优先遍历来做。
代码实现:
广度优先遍历图:

在这里插入图片描述
在这里插入图片描述

9.6 图总结

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qiqizgl777/article/details/129161216