对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

但是下面这个[1,2,2,null,3,null,3],则不是镜像对称的:

如果你可以运用递归和迭代两种方法解决这个问题,会很加分。

 

解法一: 递归

如果一个树的左子树与右子树镜像对称,那么这个树是对称的。

因此,该问题可以转化为:两个树在什么情况下互为镜像?

如果同时满足下面的条件,两个树互为镜像:

  1. 它们的两个根节点具有相同的值
  2. 每个树的右子树都与另一个树的左子树镜像对称

就像人站在镜子前审视自己那样。镜中的反射与现实中的人具有相同的头部,但反射的右臂对应于人的左臂,反之亦然。

上面的解释可以很自然地转换为一个递归函数,如下所示:

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;
}

上面就是对称二叉树的几种解法,对于第二种,第三种使用到了栈与队列,大家可以了解思想,这个题目是个很不错的题目。希望对大家有所帮助

 

posted @ 2019-10-29 23:50  国孩  阅读(252)  评论(0编辑  收藏  举报