对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3]
是对称的。
但是下面这个[1,2,2,null,3,null,3],则不是镜像对称的:
如果你可以运用递归和迭代两种方法解决这个问题,会很加分。
解法一: 递归
如果一个树的左子树与右子树镜像对称,那么这个树是对称的。
因此,该问题可以转化为:两个树在什么情况下互为镜像?
如果同时满足下面的条件,两个树互为镜像:
- 它们的两个根节点具有相同的值
- 每个树的右子树都与另一个树的左子树镜像对称
就像人站在镜子前审视自己那样。镜中的反射与现实中的人具有相同的头部,但反射的右臂对应于人的左臂,反之亦然。
上面的解释可以很自然地转换为一个递归函数,如下所示:
swift方式
public class TreeNode{ public var val: Int public var left: TreeNode? public var right: TreeNode? public init(_ val: Int){ self.val = val self.left = nil self.right = nil } } func isSymmetric(_ root: TreeNode?) -> Bool { return isMirror(root,root) } func isMirror(_ t1: TreeNode?, _ t2: TreeNode?) -> Bool{ if t1 == nil && t2 == nil { return true } if t1 == nil || t2 == nil { return false } return (t1?.val == t2?.val) && isMirror(t1?.right, t2?.left) && isMirror(t1?.left, t2?.right) }
复杂度分析:O(n)。n为树中结点的个数
解法二:迭代
我们可以换种思路,left子树是正常的先序遍历根节点 -> 左子树 -> 右子树 的顺序,对于right子树的话是根节点 -> 右子树 -> 左子树 的顺序。
所以我们可以用栈,把递归改写为迭代的形式。
public boolean isSymmetric(TreeNode root) { if (root == null) { return true; } Stack<TreeNode> stackLeft = new Stack<>(); Stack<TreeNode> stackRight = new Stack<>(); TreeNode curLeft = root.left; TreeNode curRight = root.right; while (curLeft != null || !stackLeft.isEmpty() || curRight!=null || !stackRight.isEmpty()) { // 节点不为空一直压栈 while (curLeft != null) { stackLeft.push(curLeft); curLeft = curLeft.left; // 考虑左子树 } while (curRight != null) { stackRight.push(curRight); curRight = curRight.right; // 考虑右子树 } //长度不同就返回 false if (stackLeft.size() != stackRight.size()) { return false; } // 节点为空,就出栈 curLeft = stackLeft.pop(); curRight = stackRight.pop(); // 当前值判断 if (curLeft.val != curRight.val) { return false; } // 考虑右子树 curLeft = curLeft.right; curRight = curRight.left; } return true; }
当然我们也可以使用中序遍历或者后序遍历,是一样的道理。
解法三:BFS队列
DFS 考虑完了,当然还有 BFS,一层一层的遍历两个树,然后判断对应的节点是否相等即可。利用两个队列来保存下一次遍历的节点即可。
public boolean isSymmetric6(TreeNode root) { if (root == null) { return true; } Queue<TreeNode> leftTree = new LinkedList<>(); Queue<TreeNode> rightTree = new LinkedList<>(); //两个树的根节点分别加入 leftTree.offer(root.left); rightTree.offer(root.right); while (!leftTree.isEmpty() && !rightTree.isEmpty()) { TreeNode curLeft = leftTree.poll(); TreeNode curRight = rightTree.poll(); if (curLeft == null && curRight != null || curLeft != null && curRight == null) { return false; } if (curLeft != null && curRight != null) { if (curLeft.val != curRight.val) { return false; } //先加入左子树后加入右子树 leftTree.offer(curLeft.left); leftTree.offer(curLeft.right); //先加入右子树后加入左子树 rightTree.offer(curRight.right); rightTree.offer(curRight.left); } } if (!leftTree.isEmpty() || !rightTree.isEmpty()) { return false; } return true; }
上面就是对称二叉树的几种解法,对于第二种,第三种使用到了栈与队列,大家可以了解思想,这个题目是个很不错的题目。希望对大家有所帮助