携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第15天,点击查看活动详情
一、前言
BFS
(Breath First Search
,广度优先搜索)和DFS
(Depth First Search
,深度优先搜索)是特别常用的两种算法。
DFS
算法的空间复杂度是 递归堆栈。DFS
算法其实可以被认为是 回溯算法。
DFS
模板如下: 参考回溯。
result = []; // 结果
void backtrack(路径, 选择列表) {
if (满足结束条件) {
result.add(路径);
return;
}
for (选择 : 选择列表) {
// 1. 做选择
// 2. 调用
backtrack(路径, 选择列表);
// 3. 撤销选择
}
}
二、题目
(1)二叉树中的所有路径(易)
题干分析
这个题目说的是,给你一棵二叉树,你要返回所有从根到叶子节点的路径。
# 比如说,给你的二叉树是:
1
/ \
2 4
\
8
# 在这棵二叉树中,从根到叶子节点有两条路径:
[
"1->2->8",
"1->4"
]
思路解法
思路:DFS
、回溯
- 用字符串保存遍历的路径。(字符串拼接存在拷贝的过程,即遍历中存在大量拷贝行为)
复杂度计算:
// Time: O(n^2), Space: O(n^2), Faster: 32.55%
public List<String> binaryTreePaths(TreeNode root) {
if (null == root) return Collections.emptyList();
List<String> result = new ArrayList<>();
dfs(result, root, "");
return result;
}
private void dfs(List<String> result, TreeNode root, String path) {
if (null == root) {
return;
}
if ("".equals(path)) {
path += root.val;
} else {
path += "->" + root.val;
}
if (null == root.left && null == root.right) {
result.add(path);
return;
}
dfs(result, root.left, path);
dfs(result, root.right, path);
}
优化: 使用 StringBuilder
减少字符串拷贝。
// Time: O(n*log(n)), Space: O(n), Faster: 99.97%
public List<String> binaryTreePathsV2(TreeNode root) {
List<String> result = new ArrayList<>();
dfsV2(root, new StringBuilder(), result);
return result;
}
private void dfsV2(TreeNode root, StringBuilder path, List<String> result) {
if (root == null) return;
int len = path.length();
path.append(root.val);
if (root.left == null && root.right == null) {
result.add(path.toString());
} else {
path.append("->");
dfsV2(root.left, path, result);
dfsV2(root.right, path, result);
}
path.setLength(len); // 重点,限制长度,可以认为是回溯
}
(2)二叉树的右视图(中)
题干分析
这个题目说的是,给你一棵二叉树,并且你站在这棵树的右边,你要返回从上到下看到的节点值。
# 比如说,给你的二叉树是:
1
/ \
2 4
/ \
6 8
# 站在这棵二叉树的右边看过来,从上到下看到的数字依次是:
[1, 4, 8]
思路解法
思路有二: BFS
和 DFS
方法一:BFS
- 层序遍历顺序:从左到右,一个个入队。
- 输出每一层中队列的最后一个元素即可。
// 方法一: BFS
// Time: O(n), Space: O(n), Faster: 82.03%
public List<Integer> rightSideViewBFS(TreeNode root) {
if (null == root) return Collections.emptyList();
Queue<TreeNode> queue = new LinkedList<>();
List<Integer> result = new ArrayList<>();
queue.add(root);
while (!queue.isEmpty()) {
int size = queue.size();
TreeNode node = null;
while (size-- > 0) {
node = queue.poll();
if (null != node.left) queue.add(node.left);
if (null != node.right) queue.add(node.right);
}
result.add(node.val);
}
return result;
}
方法二:DFS
- 注意递归方向: 先右子树,再左子树。
// 方法二:DFS
// Time: O(n), Space: O(n), Faster: 100.00%
public List<Integer> rightSideViewDFS(TreeNode root) {
List<Integer> result = new ArrayList<>();
dfs(root, result, 0);
return result;
}
private void dfs(TreeNode root, List<Integer> result, int level) {
if (root == null) return;
if (level == result.size()) result.add(root.val);
dfs(root.right, result, level + 1);
dfs(root.left, result, level + 1);
}