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

文章介绍了图的基本概念,包括如何用对象和数组构建图,并通过JavaScript实现了图的深度优先遍历和广度优先遍历。此外,文章还讨论了LeetCode中的相关问题,如65题的有效数字判断和133题的克隆图问题,分别展示了图在实际问题解决中的应用。
摘要由CSDN通过智能技术生成

第九章 数据结构之“图”

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 图总结

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@ZGLi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值