LeetCode 101. Symmetric Tree

本文探讨了如何判断一棵二叉树是否为中心对称,提供了递归和非递归两种解决方案,通过比较树的左右子树来实现,适用于C++和Java编程语言。

题目

Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).

For example, this binary tree [1,2,2,3,4,4,3] is symmetric:

    1
   / \
  2   2
 / \ / \
3  4 4  3

But the following [1,2,2,null,3,null,3] is not:

    1
   / \
  2   2
   \   \
   3    3

Note:
Bonus points if you could solve it both recursively and iteratively.


这道题要求一棵树是否关于它的中轴线成中心对称,刚开始想错了觉得和上一题差不多,但是发现错了以后就怎么也想不到正确的方法,感觉主要的原因一个是没有自己好好在纸上画一下、自己动手实操一下这个流程,另一个原因在于思维局限在上一题那样的一个递归函数搞定,没想到再用一个helper。

由于要求树是左右轴对称的,因此就是树的最左边应该和最右边是相对应的,而左边靠中间(也就是左边的右边)应该和右边靠中间(也就是右边的左边)相对应,也就是说,在递归的过程中,左节点的左子树和右节点的右子树是对称的,左节点的右子树和右节点的左子树是对称的,且左右两个节点的value应该相同。根据这个思路可以写出以下代码,时间复杂度O(n),空间复杂度O(n),运行时间4ms,击败97%的C++ submission:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if (!root) {
            return true;
        }
        return isSymmetricHelper(root->left, root->right);
    }
    
    bool isSymmetricHelper(TreeNode* left, TreeNode* right) {
        if (!left || !right) {
            return (left == right);
        }
        else {
            if (left->val != right->val) {
                return false;
            }
            else {
                return isSymmetricHelper(left->left, right->right) && isSymmetricHelper(right->left, left->right);
            }
        }
    }
};


另外一种是非递归做法,怎么想也想不到,然后看了大佬们的代码,越看觉得越眼熟——这特么不就是我刚刚写的Same Tree的非递归做法吗?!只是把进栈的顺序改了一下,变成相邻的一对是左边的左、右边的右,和左边的右、右边的左……立马复制粘贴刚刚的代码把最后push的顺序改了,然后把前面第一次进栈的改成root的左子节点和右子节点……十秒写完代码提交,也是4ms,时间和空间复杂度同递归算法:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if (!root) {
            return true;
        }
        
        stack<TreeNode*> stk;
        stk.push(root->left);
        stk.push(root->right);
        
        while (!stk.empty()) {
            TreeNode* first = stk.top();
            stk.pop();
            TreeNode* second = stk.top();
            stk.pop();
            
            if (!first && !second) {
                continue;
            }
            else if (!first || !second || (first->val != second->val)) {
                return false;
            }
            else {
                stk.push(first->left);
                stk.push(second->right);
                stk.push(first->right);
                stk.push(second->left);
            }
        }
        return true;
    }
    
};

那么为什么这两题的非递归做法是一毛一样的呢?接下来就归纳一下它们的相同之处:

这道题虽然只有一棵树,但是要比较的确是以这棵树第二层的两个节点为根节点的两个树是否为对称的,也就是说比较这两棵子树在特定的顺序下是否相同。Same Tree里面两棵树相同的定义为根的左子树和左子树相同、右子树和右子树相同,而Symmetric Tree里两棵树相同的定义为根的左子树和右子树相同、右子树和左子树相同。

呃……写到这里才突然发现,其实递归做法也基本一毛一样啊……只是Symmetric Tree这里由于根节点的存在而必须要加一个helper吧,helper和Same Tree的递归函数基本也是一样的,真的只是每次调用递归函数时传入的参数不同orz

我好菜.jpg


2020.10.06 Java:

一年后来做还是不会做,我好菜.jpg(10.12:我会做了)

Runtime: 0 ms, faster than 100.00% of Java online submissions for Symmetric Tree.

Memory Usage: 36.5 MB, less than 99.97% of Java online submissions for Symmetric Tree.

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        if (root == null) {
            return true;
        }
        return helper(root.left, root.right);
    }
    
    private boolean helper(TreeNode root1, TreeNode root2) {
        if (root1 != null && root2 != null) {
            return root1.val == root2.val && helper(root1.left, root2.right) && helper(root1.right, root2.left);
        } else {
            return root1 == root2;
        }
    }
}

非递归:

Runtime: 1 ms, faster than 33.18% of Java online submissions for Symmetric Tree.

Memory Usage: 38 MB, less than 14.88% of Java online submissions for Symmetric Tree.

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        if (root == null) {
            return true;
        }
        if (root.left == null || root.right == null) {
            return root.left == root.right;
        }
        Deque<TreeNode> stack1 = new ArrayDeque<>();
        Deque<TreeNode> stack2 = new ArrayDeque<>();
        stack1.push(root.left);
        stack2.push(root.right);
        while (!stack1.isEmpty()) {
            TreeNode node1 = stack1.pop();
            TreeNode node2 = stack2.pop();
            if (node1.val != node2.val) {
                return false;
            }
            if (node1.left != null && node2.right != null) {
                stack1.push(node1.left);
                stack2.push(node2.right);
            } else if (node1.left != node2.right) {
                return false;
            }
            if (node1.right != null && node2.left != null) {
                stack1.push(node1.right);
                stack2.push(node2.left);
            } else if (node1.right != node2.left) {
                return false;
            }
        }
        return true;
    }
}

2023.1.2

写出来了,但是感觉代码没有之前那么简洁,虽然效果是一样的。

递归:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        return symmetricHelper(root.left, root.right);
    }

    private boolean symmetricHelper(TreeNode left, TreeNode right) {
        if (left == null && right == null) {
            return true;
        } else if (left == null || right == null) {
            return false;
        }
        return left.val == right.val && symmetricHelper(left.left, right.right) && symmetricHelper(left.right, right.left);
    }
}
非递归:用一个stack给写出来了。为了特殊处理root里只有它自己,采用了push两次root进去的方式,感觉不会影响到代码的正确性。确实和100是很像的。
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        if (root == null) {
            return true;
        }
        Deque<TreeNode> stack = new ArrayDeque<>();
        stack.push(root);
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode right = stack.pop();
            TreeNode left = stack.pop();
            if (right.val != left.val) {
                return false;
            }
            if (right.left != null && left.right != null) {
                stack.push(right.left);
                stack.push(left.right);
            } else if (right.left != left.right) {
                return false;
            }
            if (right.right != null && left.left != null) {
                stack.push(right.right);
                stack.push(left.left);
            } else if (right.right != left.left) {
                return false;
            }
        }
        return true;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值