深度优先搜索
DFS 基本原理:
- 从根节点开始,
- 一直往左遍历,直到没有左节点,
- 然后向上找到一个没遍历过的右节点,再重复步骤2
二叉树路径和模式:
- 从根节点开始 DFS
- 如果当前节点不是叶子节点,做两件事:
- 用给定值减去当前节点的值,得到一个新值
- 带着上一步计算的值,递归调用当前节点的左右子节点
- 每一次迭代,如果当前节点是叶子节点,并且值等于给定值,返回 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 的最大长度之和。