遍历所有路径

317 阅读1分钟

题目描述

今天是奇了怪了,连着两个面试都出了涉及到遍历和递归的算法题。先看下这道题的要求吧。

对于给定的对象数组结构,描述的是一颗树的节点关系,要求实现一个函数,找出这颗树所有的链路,以二维数组形式输出:

例如:

const list = [
  { id: 6 },
  { id: 2, children: [5] },
  { id: 13 },
  { id: 5, children: [10, 11] },
  { id: 1, children: [2, 3, 4] },
  { id: 10 },
  { id: 8, children: [13] },
  { id: 4, children: [8, 9] },
  { id: 9 },
  { id: 3, children: [6, 7] },
  { id: 11, children: [14] },
  { id: 14 },
  { id: 7, children: [12] },
  { id: 12 }
];

输出:

// [
//   [ 1, 3, 6 ],
//   [ 1, 4, 8, 13 ],
//   [ 1, 2, 5, 10 ],
//   [ 1, 4, 9 ],
//   [ 1, 2, 5, 11, 14 ],
//   [ 1, 3, 7, 12 ]
// ]

意思就是从根节点开始遍历多叉树,和单纯的递归遍历不一样的地方是多了回溯。递归一般是判断是否存在某个节点或者对特定节点做一些处理,回溯是在递归的基础上找所有可行解。

编码实现

这道题在 coding 环节我是想着用 DFS 去回溯的,不过当时卡在怎么保存父节点上面,后面面试官给了一个提示说从叶子节点到根结点去访问,当时没太 get 到啥意思,后来想明白了是就是回溯的意思。

function parseArrToTree(arr) {
  //
  var root = arr.filter(item => item.id === 1)[0]
  var ans = []
  var combination = []
  dfs(root, arr, ans, combination)
  return ans
}

function dfs (root = {}, arr = [], ans = [], combination = []) {
  debugger
  if (!root.children) {
    var copy = JSON.parse(JSON.stringify(combination))
    copy.unshift(1) // 这里用了个取巧的办法,每次遍历结束把根结点添加到头部
    ans.push(copy)
    return
  }

  var children = root.children
  for (var i = 0; i < children.length; i++) {
    // 获取每个 child
    var child = children[i]
    // 保存当前存入的 child
    combination.push(child)
    var _root = arr.filter(item => item.id === child)[0]
    dfs(_root, arr, ans, combination)
    combination.pop() // 这里是回溯最重要的点:遍历结束后回退到上一个节点
  }
}

console.log('ans ===', parseArrToTree(list))