javascript数据结构 --- “图” 附leetcode算法题目

  • 图是网络结构的抽象模型,是一组由边连接的节点
  • 图可以表示任何二元关系,比如道路、航班
  • js中没有图,但是可以用Object、Array构建
  • 图的表示法:邻接矩阵、邻接表、关联矩阵
邻接矩阵

在这里插入图片描述

邻接表

在这里插入图片描述

图的常用操作

  • 深度优先遍历
    • 尽可能深的搜索图的分支
    • 算法口诀
      • 访问根节点
      • 对根节点的没访问过的相邻节点挨个进行深度优先遍历
    • code: 对此图进行深度优先遍历在这里插入图片描述
    •   	const graph = {
        		0: [1, 2],
        		1: [2],
        		2: [0, 3],
        		3: [3]
        	}
        	const visited = new Set()
        	const dfs = (n) => {
        		console.log(n) // 2 0 1 3
        		visited.add(n)
        		graph[n].forEach = (c => {
        			if (!visited.has(c)){
        				dfs(c)
        			}
        		})
        	}
        	dfs(2)
      
  • 广度优先遍历
    • 先访问离根节点最近的节点
    • 算法口诀
      • 新建一个队列,把根节点入队
      • 把队头出队并访问
      • 把队头的没有访问过的相邻节点入队
      • 重复第二、三步,直到队列为空
      • code
        •  const graph = {
           	0: [1, 2],
           	1: [2],
           	2: [0, 3],
           	3: [3]
           }
           const visited = new Set()
           visited.add(2)
           const q = [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)
           		}
           	})
           	
           }
          
    
    
    
leetcode65:有效数字 【难度:困难

在这里插入图片描述

解题思路

在这里插入图片描述
所有的字符判断可通过这张图来解释,共分为8个状态,其中淡红色的6、3、5状态为合法的数字,即题目返回true的状态;

  • 0: 即空字符串
  • 1: 由0状态转变,输入了“+”或者“-”的字符
  • 2: 由0、1状态转变,输入了小数点“.”字符
  • 6: 由1、0 转变,输入了“0~9”之间的数字
  • 3: 由2、6、3转变,6输入了小数点“.”字符, 2输入了“0~9”之间的数字,3仍输入了“0~9”之间的数字
  • 以此类推,只要最后的状态停留在6、3、5状态即为true
解题步骤
  • 构建一个表示状态的图
  • 遍历字符串中,并沿着图走,如果到了某个节点无路可走就返回false
  • 遍历结束,如走到3/5/6,就返回true,否则为false
  • code
    •  function isNumber (s) {
       	// 用blank代表空格,sign代表+/-,digit代表0~9数字
       	// 时间复杂度O(n), 空间复杂赋O(1)
       	const 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 = 'dight'
       		} else if (c === ' ') {
       			c = 'black'
       		} else if (c === '+' || c === '-' ) {
       			c = 'sign'
       		} else if (c === 'E' ) {
       			c = 'e'
       		}
       		state = graph[state][c]			
       		if (state === undefined) {
       			return false
       		}
       	}
       	if (state === 3 || state === 5 || state === 6) {
       		return true
       	}
       }
      
    
    
leetcode417:太平洋大西洋水流问题 【难度:中等

在这里插入图片描述

  • 解题思路
    • 矩阵想象成图
    • 从海岸线逆流而上遍历图,所到之处就是可以流到某个大洋的坐标
  • 解题步骤
    • 新建两个矩阵,分别记录能流到两个大洋的坐标
    • 从海岸线,多管齐下,同时深度优先遍历图,过程中填充坐标
    • 遍历两个矩阵,找出能流到两个大洋的坐标
// 时间复杂度O(m*n) 空间复杂度O(m*n) 
var atlantic = function (matrix){
	if (!matrix || !matrix[0]) return []
	const m = matrix.length // m * n 矩阵
	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)) // 记录流到太平洋的坐标
	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
}
leetcode133:克隆图 【难度:中等

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

  • 解题思路
    • 拷贝所有的节点
    • 拷贝所有的边
  • 解题步骤
    • 深度或广度优先遍历所有的节点
    • 拷贝所有的节点,存储起来
    • 将拷贝的节点,按照原图的连接方法进行连接
function cloneGraph (node) {
	// 时间复杂度O(n) 空间复杂度O(n) 
	if (!node) return 
	const visited = new Map()
	const dfs = (n) => {
		const nCopy = new Node(n.val)
		console.log(n.val)
		visited.set(n, nCopy)
		(n.neighbors || []).forEach(ne => {
			if (!visited.has(ne)) {
				dfs(ne)
			}
			nCopy.neighbors.push(visited.get(ne))
		})
	}
	dfs(node)
	return visited.get(node)
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值