翻转一棵二叉树。
解题方法:递归 + 迭代
递归
我们可以通过遍历整棵二叉树然后调换每个节点的左右子树即可完成二叉树的翻转。在递归遍历中,只有前序和后序是可以实现翻转的,因为中序的调换顺序使用的是指针,会出现一棵子树调换两次的情况。
前序遍历翻转递归代码如下:
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null){
return null;
}
//调换子树的左右节点
TreeNode node = root.left;
root.left = root.right;
root.right = node;
TreeNode left = invertTree(root.left);
TreeNode right = invertTree(root.right);
return root;
}
}
迭代
迭代写法从大体上来说可以分为两类,①使用栈深度优先遍历获取节点完成翻转。②使用队列层序遍历,对每个结点进行操作完成翻转。
代码如下:
//DFS递归
class Solution {
/**
* 前后序遍历都可以
* 中序不行,因为先左孩子交换孩子,再根交换孩子(做完后,右孩子已经变成了原来的左孩子),再右孩子交换孩子(此时其实是对原来的左孩子做交换)
*/
public TreeNode invertTree(TreeNode root) {
if (root == null) {
return null;
}
invertTree(root.left);
invertTree(root.right);
swapChildren(root);
return root;
}
private void swapChildren(TreeNode root) {
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
}
}
//BFS
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;
}
}
总结:递归三部曲,①参数、返回值 ② 递归结束条件 ③ 单层递归逻辑
给你一个二叉树的根节点 root
, 检查它是否轴对称。
解题思路:递归 + 迭代
与上题相比,这道题并不是遍历子节点问题,而是在头节点的两棵子树上进行操作。
递归:
class Solution {
public boolean isSymmetric(TreeNode root) {
return isTrue(root.left,root.right);
}
public boolean isTrue(TreeNode root1, TreeNode root2) {
//首先判断左子树和右子树的根节点存在不存在,但凡两个都为空,那就返回true;
if(root1 == null && root2 == null){
return true;
}
//如果一个左子树和右子树一个存在一个不存在,那么一定是返回false。
if(root1 == null || root2 == null){
return false;
}
//当两个子树都存在的时候,就要判断两个字数根节点的值是否相等,以及左子树的左子树和右子树的右子树,以及右子树的左子树和左子树的右子树是否为镜像子树
return root1.val == root2.val && isTrue(root1.left, root2.right) && isTrue(root1.right, root2.left);
}
}
迭代:
我们可以通过栈,也可以通过队列来进行是否是对称二叉树的判断,只不过将队列和栈的进入方式改成左子树——>先左后右,右子树——> 先右后左。从而判断连续弹出的两个元素的信息(是否为空,值是否相等)来进行结果的判断。
/**
* 迭代法
* 使用普通队列
*/
public boolean isSymmetric3(TreeNode root) {
Queue<TreeNode> deque = new LinkedList<>();
deque.offer(root.left);
deque.offer(root.right);
while (!deque.isEmpty()) {
TreeNode leftNode = deque.poll();
TreeNode rightNode = deque.poll();
if (leftNode == null && rightNode == null) {
continue;
}
if (leftNode == null || rightNode == null || leftNode.val != rightNode.val) {
return false;
}
// 这里顺序与使用Deque不同
deque.offer(leftNode.left);
deque.offer(rightNode.right);
deque.offer(leftNode.right);
deque.offer(rightNode.left);
}
return true;
}
总结:递归三部曲,①参数、返回值 ② 递归结束条件 ③ 单层递归逻辑