javascript 算法之 图 必出精品 有一定难度

785 阅读3分钟

1、介绍

2、图的深度优先遍历

  • 那么深度优先遍历的怎么实现
  • 方法论 咋们有了 那怎么实现这个方法论呢 ? 代码演示一下
  • 新建一个图 graph.js
// 新建 一个图 邻接表表示法
// 后面 value表示 可以连接到的节点
const graph = {
 0: [1, 2],
 1: [2],
 2: [0, 3],
 3: [3],
};

//使可导出
module.exports = graph;
  • dfs.js
const graph = require("./graph");
// 深度优先遍历

//建立一个新的集合 存放深度访问的节点  Set不允许重复
const visited = new Set();
const dfs = (n) => {
 //访问根节点
 console.log(n);
 visited.add(n);
 // 按照 属性进行节点遍历
 graph[n].forEach((c) => {
   if (!visited.has(c)) {
     dfs(c);
   }
 });
};

dfs(2); //  2 0 1 3

  • 当然 结果我已经显示在上面了 这次放在 node 环境执行一下

  • 符合预期 说明 深度优先遍历 没有问题

3、图的广度优先遍历

  • 来 学点新的东西 我保证你的趣味性十足
// 广度优先遍历方法展示
const graph = require("./graph");
const q = [2]; //新建队列 并将初始的节点传入
const visited = new Set(); //新建集合存放访问过的节点
visited.add(2); //添加初始值
while (q.length) {
 const n = q.shift(); // 队头出队并访问
 console.log(n); // 2 0 3 1
 graph[n].forEach((c) => {
   //遍历未访问的相邻节点
   if (!visited.has(c)) {
     q.push(c);
     visited.add(c); // 这样可以防止将重复的节点 放入集合
   }
 });
}

  • 先看一个 结果 虽然我上面展示出来了

4、leetcode 65 有效数字

  • 这个题目比较难搞 属于困难部分
  • 不过 这个题目只要能 给出这个 关系图 就好解决
/**
* @param {string} s
* @return {boolean}
* 1、新建图
* 2、建立的图的内容和实际判断对应上
* 3、新建状态 得到state = graph[state][c]
* 4、判断状态
* 时间复杂度 O(n) n指的是for循环的长度 空间复杂度为O(1) 因为有个图 但是它是固定大小的
*/
var isNumber = function(s) {
   // 新建图
   const graph = {
       0:{'blank':0, '.':2,'sign':1, 'digit':6},
       1:{'.':2, 'digit':6},
       2:{'digit':3},
       3:{'digit':3,'e':4,'E':4},
       4:{'digit':5,'sign':7},
       5:{'digit':5},
       6:{'.':3,'e':4,'digit':6,'E':4},
       7:{'digit':5}
   }
   // 需要一个记录到那里 状态的值
   var  state = 0
   // 这个地方有个小技巧 前后去掉空格不影响结果
   // 把自己写的和判断对应上
   for(c of s.trim()){
       if(c === ' '){
           c = 'blank'
       }else if(c >=0 && c <=9){
           c = 'digit'
       }else if(c === '+' || c === '-'){
           c = 'sign'
       }
       // 更新状态
       // 比如 graph[3][e] -->4
       state = graph[state][c]
       if(state === undefined){
           return false
       }
       }
       // 只有这三种情况才符合条件
       if(state === 3 || state === 5 || state === 6){
           return true
   }
   return false
};


  • nice 结果测试通过 你可以试试

5、leetcode 417 太平洋大西洋水流问题

  • 感觉是不是很神奇
  • 不要怕都是纸老虎
  • 深度优先算法
/**
* @param {number[][]} matrix
* @return {number[][]}
* 时间复杂度 O(m*n) m n 二维循环 空间复杂度 O(m*n) 两个m*n矩阵 flow1 flow2 
*/
var pacificAtlantic = function(matrix) {
   //行数或列数如果为0,则返回空数组
   if(!matrix||!matrix[0]) return [];
   //数组的行数和列数
   const m=matrix.length;
   const n=matrix[0].length;
   //初始化数组,用来记录太平洋和大西洋
   const flow1=Array.from({length:m},()=>new Array(n).fill(false));
   const flow2=Array.from({length:m},()=>new Array(n).fill(false));

   //定义dfs方法
   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);
           }
       });
   };
   //调用dfs方法
   //沿着海岸线逆流而上
   for(let r=0;r<m;r++){
       //左
       dfs(r,0,flow1);
       //右
       dfs(r,n-1,flow2);
   }

   for(let c=0;c<n;c++){
       //上
       dfs(0,c,flow1);
       //下
       dfs(m-1,c,flow2);
   }

   //收集能流到两个大洋里的坐标
   const res=[];
   for(let r=0;r<m;r++){
       for(let c=0;c<n;c++){
           if(flow1[r][c]&&flow2[r][c]){
               res.push([r,c]);
           }
       }
   }
   return res;
};

6、总结