Idiot-maker

  :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

https://oj.leetcode.com/problems/symmetric-tree/

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

For example, this binary tree is symmetric:

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

 

But the following is not:

    1
   / \
  2   2
   \   \
   3    3

 

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

解题思路:

要验证一个二叉树是不是轴对称的,我们可以直接考虑它的左右是否对称。但是好像一时半会儿想不出方法。于是想到另一个不是那么直接的方法,就是将这个树以轴做镜像变换,变换后的结果和原来的树相同,那么它就是轴对称的。

于是,这个问题可以化为两个问题,第一,如何将一个树做轴镜像变换,第二,如何判断变换后的两棵树相等。

第一个问题,将根节点的左右子节点交换,然后对它的左右子树也做这样的操作,这是一个递归的方法。第二个问题,仍然可以用递归的方法判断两棵树是否相等。但是,考虑到对root做了镜像后,root就不存在了,除非对原来的树做一个一模一样的拷贝,然后再比较它们是否相等,这样比较难。现在考虑另一个思路,将原来的树存为一个唯一的序列化表现形式,用这种方式将一棵树存下来,然后只要比较原树和变换后的树的序列化形式就可以了。这个问题在 Same Tree 的问题里讨论过,只有前序和层次遍历可以对一棵树序列化,Anagrams 这道题也是同样的思路。代码如下。

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public boolean isSymmetric(TreeNode root) {
        StringBuffer result_p = new StringBuffer();
        StringBuffer result_q = new StringBuffer();
        
        preOrder(root, result_p);
        mirrorTree(root);
        preOrder(root, result_q);
        
        return result_p.toString().equals(result_q.toString());
    }
    
    public void mirrorTree(TreeNode root){
        if(root == null){
            return;
        }
            
        TreeNode leftNode = root.left;
        root.left = root.right;
        root.right = leftNode;

        mirrorTree(root.left);
        mirrorTree(root.right);
    }
    
    public void preOrder(TreeNode root, StringBuffer result){
        if(root == null){
            result.append("#");
            return;
        }
        result.append(root.val);
        preOrder(root.left, result);
        preOrder(root.right, result);
    }
}

这个方法用了两次递归,当然序列化的方法preOrder是可以迭代的。考虑一下有么有其他更直接的方法?

我们再来看看轴对称的定义。一棵树是轴对称的,那么它的左右子树一定是对称的。要注意,这里将判断一棵树是否关于轴对称的问题,转化为判断两棵树是否为轴对称的树的问题,这是一个与原题相似却不同的问题。这样,虽然原题不太好直接写成一个递归的方法,但是,判断两棵树轴对称,这就是一个递归的问题了。

A、B树互为轴对称,那么他们的根节点一定相等,而且A的左子树和B的右子树一定互为轴对称,A的右子树和B的左子树也互为轴对称。这就是一个递归的定义了。代码如下。

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null){
            return true;
        }
        return isMirrorTree(root.left, root.right);
    }
    
    public boolean isMirrorTree(TreeNode p, TreeNode q){
        if(p == null && q == null){
            return true;
        }
        if(p != null & q != null && p.val == q.val){
            return isMirrorTree(p.left, q.right) && isMirrorTree(p.right, q.left);
        }else {
            return false;
        }
    }
}

我们看到,这个解法的巧妙之处在于,考虑一棵树是否轴对称不容易转化为递归,但是考虑两棵树是否互为轴对称就容易多了。

原题还要求一个迭代的解法。借助上面的思路,我们可以对原树进行level order的遍历,将每层的遍历结果保存成一个String[],对于null的节点,插入一个特殊的字符,比如“#”。这样,对每层的结果,判断它们是不是轴对称就可以了。

需要注意的有几个细节,一个是这个String[]数组的大小,和插入字符的下标。还有这个结果一定不能用StringBuffer,在后面直接append。否则遇到两位数,或者负数,加起来就无法判断是否轴对称了。要以某种形式将其分割才可以。

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public boolean isSymmetric(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        
        if(root == null){
            return true;
        }
        
        queue.add(root);
        
        while(queue.size() != 0){
            int levelSize = queue.size();
            
            //这里只能用String[],不能用StringBuffer
            //否则遇到1,-54,#,-54,1这种从两头开始无法比较是否对称
            //数组的size要注意是levelSize * 2
            String[] levelCode = new String[levelSize * 2];
            
            while(levelSize > 0){
                TreeNode temp = queue.poll();
                if(temp.left != null){
                    queue.offer(temp.left);
                    //要注意数组的下标
                    levelCode[levelSize * 2 - 1] = String.valueOf(temp.left.val);
                }else{
                    levelCode[levelSize * 2 - 1] = "#";
                }
                if(temp.right != null){
                    queue.offer(temp.right);
                    levelCode[levelSize * 2 - 2] = String.valueOf(temp.right.val);
                }else{
                    levelCode[levelSize * 2 - 2] = "#";
                }
                levelSize--;
            }
            
            //判断levelCode是否轴对称
            int start = 0;
            int end = levelCode.length - 1;
            
            while(start < end){
                if(!levelCode[start].equals(levelCode[end])){
                    return false;
                }
                start++;
                end--;
            }
        }
        return true;
    }
}

 

posted on 2015-03-02 19:20  NickyYe  阅读(205)  评论(0编辑  收藏  举报