102. 二叉树的层序遍历
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
思路
递归法和迭代法都是DFS,而层序遍历是BFS。我们可以借助队列来实现,队列是先进先出符合广度优先 遍历。具体思路如下:
假设我们有以下这棵树:
我们维护一个队列 以及一个
size,这个size代表的是当前层数还剩多少个元素没有弹出;如上图第一步,6 是头节点的元素,头节点这层只有一个元素,因此size = 1; 再如第三步,7 是第二层的最后一个元素,因此第二层只有一个元素没有弹出,因此 size = 1
了解了以上两点之后,我们具体描述一下我们的操作步骤:
- 首先将头节点插入队列,更新
size = 1; - 然后弹出队列的头节点,并把该节点加入
list,并将其所有孩子节点以从左到右的顺序插入队列尾部,并更新size--,直至当前层数的所有节点被弹出,这时size = 0;同时队列里存在的所有节点都是下一层的节点(例如图内第四步),因此更新size = queue.size()并且创建一个新的列表list = new ArrayList<>()用于储存新的一层的元素。 - 重复这个过程直至所有节点都被遍历。
- 最后我们就得到了结果集。
代码实现
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) return res;
Queue<TreeNode> dq = new LinkedList<>();
dq.offer(root);
while (!dq.isEmpty()) {
int len = dq.size();
List<Integer> list = new ArrayList<>();
while (len > 0) {
TreeNode node = dq.poll();
list.add(node.val);
if (node.left != null) {
dq.offer(node.left);
}
if (node.right != null) {
dq.offer(node.right);
}
len--;
}
res.add(list);
}
return res;
}
}
226. 翻转二叉树
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
思路
依次翻转每个节点的左右节点,直至叶子节点为止。
可以使用前序遍历和后续遍历完成。
代码实现
class Solution {
public TreeNode invertTree(TreeNode root) {
recursion(root);
return root;
}
private void recursion(TreeNode root) {
if (root == null) return;
// 对当前结点的处理逻辑
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
if (root.left != null) recursion(root.left);
if (root.right != null) recursion(root.right);
}
}
补充
在做二叉树相关的题目的时候,首先思考的是我们遍历时应该用何种遍历方法,前,中,后序遍历亦或者是层序遍历?
- 涉及到二叉树的构造,无论普通二叉树还是二叉搜索树一定前序,都是先构造中节点。
- 求普通二叉树的属性,一般是后序,一般要通过递归函数的返回值做计算。
- 求二叉搜索树的属性,一定是中序了,要不白瞎了有序性了。
注意在普通二叉树的属性中,我用的是一般为后序,例如单纯求深度就用前序,二叉树:找所有路径 (opens new window)也用了前序,这是为了方便让父节点指向子节点。
所以求普通二叉树的属性还是要具体问题具体分析。
摘自代码随想录
101. 对称二叉树
给你一个二叉树的根节点 root , 检查它是否轴对称。
思路一:
使用广度优先算法,求出每一层的所有的元素。然后使用双指针来判断每一层是否是回文。
代码实现-思路一
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
return bfs(root);
}
boolean bfs(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
Queue<TreeNode> que = new LinkedList<>();
que.offer(root);
while (!que.isEmpty()) {
int len = que.size();
List<Integer> list = new ArrayList<>();
while (len-- > 0) {
TreeNode node = que.poll();
if (node != null) {
que.offer(node.left);
que.offer(node.right);
list.add(node.val);
} else {
list.add(null);
}
}
res.add(list);
}
boolean ans = false;
for (List<Integer> list: res) {
ans = isSym(list);
if (ans == false) {
return false;
}
}
return ans;
}
boolean isSym(List<Integer> list) {
// System.out.println(list);
int l = 0;
int r = list.size() - 1;
while (l <= r) {
if (list.get(l) != list.get(r)) return false;
l++;
r--;
}
return true;
}
}
思路二
使用后序遍历。
要比较是否对称,我们要比较的是两个子树的内侧和外侧节点是否相等,如下图:
通过这张图我们可以得知我们的递归三要素:
- 确定递归函数的参数和返回值
因为要比较的是根节点的左子树与右子树是否是对称的,因此参数为根节点的左右节点,返回值为
bool类型
- 确定终止条件
首先要判断是什么时候返回
false,什么时候返回true
- 左节点为空,右节点不为空,返回
false- 左节点不为空,右节点为空,返回
false- 左节点为空,右节点也为空,返回
true- 左右节点都不为空,但是左右节点数值不同, 返回
false此时左右节点不为空,且数值也不相同的情况我们也处理了。 代码如下
if (left == null && right != null) return false;
if (left != null && right == null) return false;
if (left == null && right == null) return true;
if (left.val != right.val ) return false;
- 单层递归逻辑
此时左右节点都不为空,且左右节点的值都相同;
- 此时我们就要比较二叉树外侧是否对称,要比较的是左节点的左孩子和右节点的右孩子
- 二叉树内侧是否相同,要比较的是左节点的右孩子和右节点的左孩子
- 如果内外侧都相同则返回
true否则返回false
代码实现为:
boolean outside = compare(left.left, right.right);
boolean inside = compare(left.right, right.left);
return outside && inside;
代码实现-思路二
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
boolean recursion = compare(root.left, root.right);
return recursion;
}
boolean compare(TreeNode left, TreeNode right) {
if (left == null && right != null) return false;
if (left != null && right == null) return false;
if (left == null && right == null) return true;
if (left.val != right.val ) return false;
// 当此层相等,我们就要判断下一层是否相等
boolean outside = compare(left.left, right.right);
boolean inside = compare(left.right, right.left);
return outside && inside;
}
}