深度优先搜索

320 阅读4分钟

深度优先搜索

DFS 基本原理

  1. 从根节点开始,
  2. 一直往左遍历,直到没有左节点,
  3. 然后向上找到一个没遍历过的右节点,再重复步骤2

二叉树路径和模式

  1. 从根节点开始 DFS
  2. 如果当前节点不是叶子节点,做两件事:
  • 用给定值减去当前节点的值,得到一个新值
  • 带着上一步计算的值,递归调用当前节点的左右子节点
  1. 每一次迭代,如果当前节点是叶子节点,并且值等于给定值,返回 true;否则返回 false
  • 112. 路径总和 easy -- done (短路求值避免多余的递归)
  • 113. 路径总和 II medium -- done (时间复杂度和空间复杂度的计算)
  • 437. 路径总和 III -- done
    • 思路1:先递归遍历每个节点,再以每个节点作为起点寻找满足条件的路径。注意,非叶子节点满足要求后,还要继续往下找。
    • 思路2:遍历所有的 root-to-leaf 路径。每到达一个叶节点,就得到一个 root-to-leaf 的数组,然后穷举这个数组,检查是否有满足要求的连续子序列。
    • 思路3:对思路2的改进。维护一个当前路径的数组,每遇到一个节点,就将其添加到数组中,然后穷举所有以该节点为末尾的连续子序列。如果存在等于给定值的子序列,就递增数量。注意,当我们向上回溯时,需要从数组中删除当前节点
    • 思路3是对思路2的改进,思路1和思路3本质上相反,一个正向,一个逆向。
    • 时间复杂度:我们遍历了每个节点一次。另外,我们还遍历了当前路径。最好时间复杂度为 O(N)*O(logN)=O(NlogN),最坏时间复杂度为 O(N)*O(N)=O(N*N)
    • 空间复杂度:不考虑递归栈的空间,当前路径最坏情况下为 O(N);最好情况为 O(logN)
  • 666. 路径总和 IV -- ing
  • 129. 求根节点到叶节点数字之和 medium -- done
    • 需改进的点:我用了数组来追踪路径上的所有节点,所以花费了额外的内存,空间复杂度是O(logN)。实际上,可以将它们压缩成数字,这样空间复杂度就变为了O(1)。
    • 如何将一个序列转化为数字:例如 [1,2,3],怎么变成 123。其实就是 0*10+1=1; 1*10+2=12;12*10+3=123
    • 这道题最好看下题解 -- ing
  • 1430. 判断给定的序列是否是二叉树从根到叶的路径 -- done
    • 关键点是递归的终止条件,包括给定序列与节点值不匹配;给定序列大于 root-to-leaf 的长度;给定序列小于 root-to-leaf 的长度。
  • 257. 二叉树的所有路径 easy -- done
  • 124. 二叉树中的最大路径和 hard -- done
  • 思路1:总的来说,就是遍历每一棵子树,算出每棵子树的最大路径和,最后比较得到整棵树的最大路径和。
  • 思路2:每棵子树的最大路径和一定过根节点,需要比较根节点,根节点+左子树最大路径,根节点+右子树最大路径,根节点+左子树最大路径+右子树最大路径这四种情况得到最大值。其实,如果没有负数,经过根节点的最长路径和计算方式是:根节点+左子树最大路径+右子树最大路径。一种简化的方法就是将负数变为0。
  • 思路3:在回溯过程中,子树的父节点需要子树经过根节点的最长边。这个边从父节点指向子节点,不能分叉。
  • 543. 二叉树的直径 -- done
    • 思路1:遍历树的每个节点,以该节点为根节点,计算直径,比较所有子树的直径,获得最大直径。每个子树的直径等于其左、右子树 root-to-leaf 的最大长度之和。