JAVA二刷-Day15 | 层序遍历*10, 226.翻转二叉树, 101.对称二叉树
层序遍历
LeetCode题目:
102.二叉树的层序遍历
107.二叉树的层次遍历II
199.二叉树的右视图
637.二叉树的层平均值
429.N叉树的层序遍历
515.在每个树行中找最大值
116.填充每个节点的下一个右侧节点指针
117.填充每个节点的下一个右侧节点指针II
104.二叉树的最大深度
111.二叉树的最小深度
解题思路
层序遍历的方法都比较类似,因为首先要对每一层的元素进行维护,因此需要用容器来进行存储,同时容器在获取元素的同时,应当将该元素节点的子节点放入容器中。如果直接用容器内部的size来判定是否取完该层节点,则会出现因为不断增加子节点无法分层。因此需要在获取子节点之前先确定容器当前的size,以此来判定是否取完了当前层的节点。
此外,层节点要取出,应该遵循的是FIFO原则,因此要使用队列进行存储,以下是102的代码:
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
Queue<TreeNode> queTree = new LinkedList<TreeNode>();
List<List<Integer>> result = new ArrayList<>();
TreeNode node;
if (root != null) queTree.offer(root);
while (!queTree.isEmpty()) {
int size = queTree.size();
List<Integer> resultLevel = new ArrayList<>();
for (int i = 0; i < size; i++) {
node = queTree.peek();
queTree.poll();
if (node.left != null) queTree.offer(node.left);
if (node.right != null) queTree.offer(node.right);
resultLevel.add(node.val);
}
result.add(resultLevel);
}
return result;
}
}
进阶:117.填充每个节点的下一个右侧节点指针II
LeetCode题目链接:https://leetcode.cn/problems/minimum-depth-of-binary-tree/
解题思路
按照题目中进阶要求,使用O(1)的空间复杂度完成代码,同时不考虑递归所产生的额外函数栈空间,因此首选使用递归来完成。因此,每次递归root节点,都可以将接下来的root下的子节点的next关系进行获得。
但存在一些问题,即递归的时候,左子树部分的next关系依赖于右子树父节点的next关系。如果递归先遍历左子树进行操作。那么会直接循环到左子树的地步,此时中间层的右子树next关系还没有构建出来。因此会造成next没有完全。
因此需要先递归右子树,再递归左子树,代码如下:
class Solution {
public Node getNext(Node root) {
if (root == null) return null;
if (root.left != null) {
return root.left;
}else if (root.left == null && root.right != null) {
return root.right;
}else {
return getNext(root.next);
}
}
public Node connect(Node root) {
if (root == null) return root;
if (root.left != null && root.right !=null) {
root.left.next = root.right;
}else if (root.left != null && root.right == null) {
root.left.next = getNext(root.next);
}
if (root.right != null) {
root.right.next = getNext(root.next);
}
connect(root.right);
connect(root.left);
return root;
}
}
翻转二叉树
LeetCode题目链接:https://leetcode.cn/problems/invert-binary-tree/
解题思路
迭代法可以使用层序遍历的方法逐层次进行翻转。递归方法使用时候要注意中序遍历的特殊情况。
具体代码如下:
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
root.left = invertTree(root.left);
root.right = invertTree(root.right);
return root;
}
}
对称二叉树
LeetCode题目链接:https://leetcode.cn/problems/symmetric-tree/
解题思路
对称二叉树在进行比较的时候,应当从最末尾处逐级返回是否匹配成功,如果一个匹配不成功false,结果应当也返回false。同时,因为要涉及左右两个分支的对比,所以应当使用递归的方法来进行逐级的比较和返回。
在对比左右子树的节点对称时候,应当左子树的左节点与右子树的右节点对比。左子树的右节点和右子树的左节点进行对比,当两次对比均相同才能说明该层对称。因此应当使用&&进行两次对比后判定结果。同时,当子树对称,且子节点不为空时候,才有必要继续递归,所以递归的条件只有left.val==right.val的时候。
具体代码如下:
class Solution {
public boolean compare(TreeNode right, TreeNode left) {
if (left == null && right != null) {
return false;
}else if (left != null && right == null) {
return false;
}else if (left == null && right == null) {
return true;
}else if (left.val != right.val) {
return false;
}
boolean outside = compare(right.right, left.left);
boolean inside = compare(right.left, left.right);
return outside&&inside;
}
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
return compare(root.right, root.left);
}
}
如果使用迭代法,则需要注意将需要对比的两个元素放在邻近位置,以便于对比是否对称。同时,对比后即可弹出,因此使用队列来进行。
代码如下:
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
Queue<TreeNode> queTree = new LinkedList<>();
TreeNode node = root;
queTree.offer(root.left);
queTree.offer(root.right);
while (!queTree.isEmpty()) {
TreeNode leftNode = queTree.peek();
queTree.poll();
TreeNode rightNode = queTree.peek();
queTree.poll();
if (leftNode == null && rightNode == null) {
continue;
}
if (leftNode == null && rightNode != null) {
return false;
}else if (leftNode != null && rightNode == null) {
return false;
}else if (leftNode.val != rightNode.val) {
return false;
}
queTree.offer(leftNode.left);
queTree.offer(rightNode.right);
queTree.offer(leftNode.right);
queTree.offer(rightNode.left);
}
return true;
}
}