代码随想录 101.对称二叉树
1.问:什么样的题目采用后序遍历?
答:需要收集孩子的信息,向上一层返回的题目。具体来说,左右中的遍历顺序,可以使二叉树先收集左孩子的信息和右孩子的信息,中的处理过程中则会将孩子的处理信息向上一层返回。
2.弄清楚要比较的节点,要比较的节点并非左右节点,而是根节点的左右子树是否是可以相互翻转的,即要比较的是根节点的左右子树。
3.如何比较? 比较两个子树的里侧和外侧元素是否相等,如图所示。
4.由于要通过递归函数的返回值判断两个子树的内侧节点和外侧节点是否相等,所以应采用后序遍历。具体来说,要遍历两棵树而且要比较内侧和外侧节点,准确来说一个树的遍历顺序是左中右,一个树的遍历顺序是右左中。
方法一:
DFS递归:采用后序遍历的思想。
1.确定参数和返回值:
(1)参数:因为要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两棵树,参数自然也是左子树节点和右子树节点。
(2)返回值:自然是bool类型。
boolean compare(TreeNode left, TreeNode right)
2.确定终止条件:先考虑有节点为空的情况,剩下的情况就是左右节点都不为空的情况。
(1)左节点为空,右节点不为空,不对称,return false
(2)左节点不为空,右节点为空,不对称,return false
(3)左右节点都为空,对称,return true
(4)剩下的就是左右节点都不为空的情况:左右节点都不为空,比较节点数值,不相同就return 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;}
3.确定单层递归的逻辑:单层递归的逻辑用来处理左右节点都不为空,且数值相同的情况。
(1)比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子;
(2)比较内侧是否对称:传入左节点的右孩子,右节点的左孩子;
(3)如果左右都对称就返回true,一侧不对称就返回false;
// 比较外侧boolean compareOutside = compare(left.left, right.right);// 比较内侧boolean compareInside = compare(left.right, right.left);return compareOutside && compareInside;
(4)上述代码可以看出使用的遍历方式,左子树左右中,右子树右左中,所以这个遍历顺序并非严格的“后序遍历”。
附代码:
class Solution {public boolean isSymmetric(TreeNode root) {return compare(root.left,root.right);}public 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 compareOutside = compare(left.left,right.right);//比较内侧 左子树:右 右子树:左boolean compareInside = compare(left.right,right.left);//逻辑处理 左子树:中 右子树:中//逻辑与,只有外侧和内侧都对称,这棵二叉树才对称return compareOutside && compareInside; }
}
方法二:
迭代实现,使用队列来比较两个树(根节点的左右子树)是否相互翻转,这里并非层序遍历。通过队列判断根节点的左子树和右子树的内侧和外侧是否相等。
附代码:
class Solution {public boolean isSymmetric(TreeNode root) {LinkedList<TreeNode> queue = new LinkedList<>();if(root == null){return true;}queue.add(root.left);queue.add(root.right);while(queue.size()>0){TreeNode leftNode = queue.remove();TreeNode rightNode = queue.remove();//左右节点都为空if(leftNode == null && rightNode == null){continue;}//其他三个情况合并if(leftNode == null || rightNode == null || leftNode.val != rightNode.val){return false;}//注意队列放入顺序,通过队列判断左子树和右子树的内侧和外侧是否相等queue.add(leftNode.left);queue.add(rightNode.right);queue.add(leftNode.right);queue.add(rightNode.left);}return true;}
}