二叉树的层序遍历(广度优先遍历)

link:102. 二叉树的层序遍历 - 力扣(LeetCode)

思路分析

题目说明从左往右进行遍历,其实可以堪称给二叉树每一层都画横线分割开来,left first,right last.

image-20241108151829868

n代表null 输出只从存在的节点中输出.
最先想到的就是递归,按照创建树的思路,pass掉空节点就好.
先前做过队列模拟栈,其实这里用队列来解决也很优雅.

队列BFS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ret = new ArrayList<>();
if(root == null) {
return ret;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
//获取当前队列的大小
int size = queue.size();
List<Integer> tmp = new ArrayList<>();
while(size != 0) {
TreeNode cur = queue.poll();
tmp.add(cur.val);
size--;
if(cur.left != null) {
queue.offer(cur.left);
}
if(cur.right != null) {
queue.offer(cur.right);
}
}
ret.add(tmp);
}
return ret;
}
}

Tips
高度:二叉树中任意一个节点到叶子结点的距离
深度:二叉树中任意一个节点到根节点的距离

List<List<Integer>> 的必要性

每一层的节点值需要单独存储在一个列表中,然后将所有层的列表整合在一个大列表中。因此,最终结果需要一个嵌套的列表结构。

反转二叉树

link:226. 翻转二叉树 - 力扣(LeetCode)

思路分析

根据题意,看到的是左右子树内部交换自身孩子节点,然后左右子树又进行了交换.
递归交换就秒了.
其实可以老老实实的逐个左右交换,也可以按照上一题层序遍历的一层层交换(观察到最后一层是1,3,6,9——>9,6,3,1)

DFS(递归)

注意前序遍历和后序遍历可以,中序遍历不行(不信你就画图推推看)
前序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null) {
return null;
}
TreeNode tmp = root.left;
root.left= root.right ;
root.right = tmp;


invertTree(root.left);
invertTree(root.right);

return root;
}
}

后序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) {
return null;
}

// 后序遍历:先递归地翻转左右子树
TreeNode left = invertTree(root.left);
TreeNode right = invertTree(root.right);

// 交换左右子树
root.left = right;
root.right = left;

return root;
}
}
BFS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) {return null;}
ArrayDeque<TreeNode> deque = new ArrayDeque<>();
deque.offer(root);
while (!deque.isEmpty()) {
int size = deque.size();
while (size-- > 0) {
TreeNode node = deque.poll();
swap(node);
if (node.left != null) {deque.offer(node.left);}
if (node.right != null) {deque.offer(node.right);}
}
}
return root;
}

public void swap(TreeNode root) {
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
}
}

Tips

人机有话说.
DFS 和 BFS 的区别

  1. 遍历顺序
    • DFS(Depth First Search,深度优先搜索):优先深入到每个节点的子节点,通常会先访问到某个分支的最底层节点,然后再回溯到上层节点去访问其他分支。常见的 DFS 实现有三种:前序遍历(Preorder)、中序遍历(Inorder)、后序遍历(Postorder)。
    • BFS(Breadth First Search,广度优先搜索):优先访问每一层的节点,然后再逐层深入。BFS 一般使用队列(Queue)来实现,按层次逐一处理节点。
  2. 数据结构
    • DFS:常用递归或栈来实现,递归会隐式使用系统栈,而非递归的实现需要显式的栈。
    • BFS:通常使用队列来实现,因为它按照层次顺序访问节点。
  3. 时间复杂度和空间复杂度
    • 时间复杂度:DFS 和 BFS 的时间复杂度都是 O(n),其中 nnn 是节点的数量,因为每个节点都需要被访问一次。
    • 空间复杂度:DFS 的空间复杂度取决于递归的深度,最坏情况下是 O(h)(树的高度);BFS 的空间复杂度则是 O(w),其中 w是树的最大宽度。

对称二叉树

link:101. 对称二叉树 - 力扣(LeetCode)

思路分析

看题目确实觉得很对称啊,看图分析左子树和右子树的遍历顺序,左子树是左右中,那和右子树比较的时候就是右左中.
特殊情况优先考虑
左空右空->true
左不空右空->false
左空右不空->false
那最后的情况就是左右都不为空了,这时候就需要单独判断.
单侧不对称就可以返回false.
那么这么比较就只能是后序遍历了.
递归秒!

递归
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
return cmp(root.left,root.right);
}
boolean cmp(TreeNode left,TreeNode right) {
if(left == null && right == null) {
return true;
}else if(left == null && right != null) {
return false;
}else if(left != null && right == null) {
return false;
}else if(right.val != left.val){
return false;
}
boolean last = cmp(left.left,right.right);
boolean lastnext = cmp(left.right,right.left);
return last && lastnext;
}
}

注意
不要else if判断结束之后直接else{return true;}
这样做的话没有判断其他剩余的子节点 ,意味着中层节点的值心相等,但是叶子节点的值不通,但仍然判断这种情况为true,这样是不对的.