• 对称二叉树


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

    例如,二叉树 [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;
    }

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

  • 相关阅读:
    团队的展示以及规划
    基于上次数独基础优化,并添加GUI界面
    利用程序随机构造N个已解答的数独棋盘
    本学期高级软件工程课程的实践项目的自我目标
    本学期高级软件工程课程的实践项目的自我目标
    案列分析
    编程作业
    构建之法
    软工一
    小黄衫获奖感言
  • 原文地址:https://www.cnblogs.com/guohai-stronger/p/11762230.html
Copyright © 2020-2023  润新知