作者:CQF
📔DFS概念:深度优先遍历(Depth First Search,简称 DFS)
图论中两种非常重要的算法,生产上广泛用于拓扑排序、寻路(走迷宫)、搜索引擎、爬虫等。
1. DFS案例1——具体树
- 查找父节点
点击节点时,带出父级以上节点名称
看看主流组件库怎么实现?
element-ui el-menu组件实现(el-tree没有实现)
// https://github.com/ElemeFE/element/blob/dev/packages/menu/src/menu-mixin.js indexPath() {
const path = [this.index];
let parent = this.$parent;
while (parent.$options.componentName !== 'ElMenu') {
if (parent.index) {
// 关键代码,父元素记录了index
path.unshift(parent.index);
}
parent = parent.$parent;
}
return path;
}
ant-design实现了react-component的rc-menu组件实现
const getSubPathKeys = useCallback((key: string): Set<string> => {
const connectedPath = `${key2pathRef.current.get(key)}${PATH_SPLIT}`;
const pathKeys = new Set<string>();
[...path2keyRef.current.keys()].forEach(pathKey => {
if (pathKey.startsWith(connectedPath)) {
pathKeys.add(path2keyRef.current.get(pathKey));
}
});
return pathKeys;
}, []);
数据结构实现
function findParentLabel({ label }) {
this.visitNodeList = []
const dfs = (list, target, queue = []) => {
for (let i = 0; i < list.length; i++) {
let node = list[i]
this.visitNodeList.push(node.label)
if (node.label === target) {
return [...queue, node.label]
}
if (node.children && node.children.length) {
let result = dfs(node.children, target, [...queue, node.label])
if (result && result.length) {
return result
}
}
}
}
}
2. DFS案例2——抽象树:排列组合
- 全排列
- [1,2,3]
- [1,2,3] [1,3,2] [2,1,3] [2,3,1] [3,1,2] [3,2,1]
- 组合 n选m
- [1,2,3]
- [1,2] [1,3] [2,3] 全排列图解如下
全排列图解操作如下
排列解题代码模板,即数字可重复的模板
function DFS (nums, stack) {
if (满足添加) {
// 处理逻辑
}
for (let i = 0; i < nums.length; i++) {
cur = 出队()
入栈(cur)
DFS(队列, 栈)
出栈()
归队(cur)
}
}
- 📒 案例: 给定无序、不重复的数组data,取出 n 个数,使其相加和为sum
- [9, 5, 4, 2, 6, 7, 1]
- 3
- 16
组合解题代码模板,即数字不可重复的模板
function DFS (nums, start, stack) {
if (满足添加) {
// 处理逻辑
}
for (let i = start; i < nums.length; i++) {
入栈(cur)
DFS(队列,下标,栈)
出栈(cur)
}
}
💪🏻 万能模板
funcion DFS () {
if (满足条件) {
// 处理逻辑
}
if(剪枝条件) {
// 剪枝
}
for (选择 in 选择列表) {
做选择
DFS()
撤销选择
}
}
📔BFS概念:广度优先遍历(Breath First Search,简称 BFS)
Note: 能干嘛 最短路径 最少步数最近节点
解题模板
ffunction BFS (root) {
入队(root)
while (队列.length > 0) {
len = 记录队列长度
for (遍历队列) {
cur = 出队()
if (cur.子节点) {
入队(cur.子节点)
}
}
}
}
📒 综合练习案例
- 数字n代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且有效的括号组合。
- 分别用DFS和BFS实现
- n = 3
- ["((()))", "(()())", "(())()", "()(())", "()()()"]
function dfs (n) {
let result = []
// left表示剩余左括号的数量
function dfs(left, right, str = '') {
if (left === 0 && right === 0) {
result.push(str)
return
}
if (left > right) {
return
}
left > 0 && dfs(left - 1, right, str + "(")
right > 0 && dfs(left, right - 1, str + ')')
}
dfs(n, n)
return result
}
function bfs (n) {
let queue = [{
str: '(',
left: 1,
right: 0
}]
let result = []
while (queue.length) {
let len = queue.length
for (let i = 0; i < len; i++) {
let cur = queue.shift()
if (cur.left === n && cur.right === n) {
result.push(cur.str)
continue
}
if (cur.left >= cur.right && cur.left < n) {
queue.push({
str: cur.str + '(',
left: cur.left + 1,
right: cur.right
})
}
if (cur.left > cur.right) {
queue.push({
str: cur.str + ')',
left: cur.left,
right: cur.right + 1
})
}
}
}
// console.log(result);