【回溯法】treeNode 里面找目标节点及路径

936 阅读1分钟

回溯法很好用,可以查找出全部符合目标的答案,属于暴力求解的一种。

const tree = [
  {
    id: '1',
    name: '广东省',
    children: [
      {
        id: '11',
        name: '深圳市',
        children: [
          {
            id: '111',
            name: '南山区',
          },
          {
            id: '112',
            name: '南山区',
          },
        ],
      },
      {
        id: '12',
        name: '广州市',
        children: [
          {
            id: '121',
            name: '天河区',
          },
          {
            id: '122',
            name: '越秀区',
          },
        ],
      },
    ],
  },
  {
    id: '2',
    name: '江西省',
    children: [
      {
        id: '21',
        name: '南昌市',
        children: [
          {
            id: '211',
            name: '南昌1区',
          },
          {
            id: '212',
            name: '南昌2区',
          },
        ],
      },
      {
        id: '22',
        name: '赣州市',
        children: [
          {
            id: '221',
            name: '赣州1区',
          },
          {
            id: '222',
            name: '赣州2区',
          },
        ],
      },
    ],
  },
];

查找目标节点

直接深度遍历即可,简单。

const findTargetNode = targetId => {
  let res = null;
  function dfs(targetId, item) {
    if (item.id === targetId) {
      res = item;
      return;
    }
    if (item.children?.length) {
      item.children.forEach(subItem => {
        dfs(targetId, subItem);
      });
    }
  }
  const root = { id: 'NONE', children: tree };
  dfs(targetId, root);
  return res;
};

findTargetNode('112') // => { id: '112', name: '南山区' }
findTargetNode('222') // => { id: '222', name: '赣州2区' }
findTargetNode('333') // => null
findTargetNode('21') // =>
// {
//   id: '21',
//   name: '南昌市',
//   children: [ { id: '211', name: '南昌1区' }, { id: '212', name: '南昌2区' } ]
// }}

查找包含目标节点的路径

使用回溯法可以轻松搞定。(这里假设目标节点就是叶子节点,如果不是叶子节点那么只能返回自顶到目标节点的路径)

const findPath = targetId => {
  let res = [];
  function dfs(targetId, item, subPath) {
    if (subPath.includes(targetId)) {
      res = JSON.parse(JSON.stringify(subPath)); // 地址引用,这里一定要深拷贝
      return;
    }
    if (item.children?.length) {
      item.children.forEach(subItem => {
        subPath.push(subItem.id);
        dfs(targetId, subItem, subPath);
        subPath.pop();
      });
    }
  }

  const root = { id: 'NONE', children: tree };
  dfs(targetId, root, []);
  return res;
};
findPath('112'); // => [1, 11, 112]
findPath('222'); // => [2, 22, 222]
findPath('333'); // => []
findPath('21'); // => [ '2', '21' ]

完成