LeetCode对称二叉树

二叉树镜像对称问题的递归与非递归解法
博客围绕判断二叉树是否镜像对称展开,提出用递归和非递归两种方法解决。先阐述递归思路,即对比根节点左右孩子对应节点的值;又探讨非递归方法,指出存值不可行,考虑存节点进数组再判断数组值是否相同。

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

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

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

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

   1
 /    \
2      2
\       \
  3      3

请用递归和非递归两种方法解决问题。

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

    }
}

这种题第一印象是什么?拿到后应该怎么做?

我的第一印象,是分别让根节点的左右两个孩子分别作为一颗新的树,然后按照一定的方式遍历,对比二者的值,判断是否相等。天不遂人愿,总有测试样例通过不了。细究,是因为遍历出来的值顺序并不一定和原始的排序顺序相等。看如下用例:

        1
    /      \
   2        2
  /         / 
  2        2

它并不对称,但是遍历出的子树均为[2,2],如果将null值也记录起来,则不得不记录当前节点的层数。只有当这一层有其他节点非空的时候,才会将这一层的值都记录下来。是不是太麻烦了,这毕竟是个简单题。

再审视一下树的结构:

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

当我们对比的时候,比较的是root.leftroot.right,然后比较root.left.leftroot.right.rightroot.left.rightroot.right.left。如果树再高点,就是继续划分。但是用代码可以写成:

if(root.left == root.right)
	left = root.left
	right = root.right
if(left.left== right.right && left.right == right.left)
	leftl = left.left
	leftr = left.right
	rightl = right.left
	rightr = right.right
if(...)

有点递归的意思了。

那我们先写一个比较代码:

boolean cmp(TreeNode a, TreeNode b){
	if(a != null && b!= null){
		if(a.val != b.val){
			return false;
		}
		if(a.val == b.val){
			return true;
		}
	}else if(a== null && b == null){
		return true;
	}else{
		return false;
	}
}

然后我们看看递归应该往哪放。
递归必然是在上一层都相等的情况下判断下一层是否相等,否则直接跳出即可。

boolean cmp(TreeNode a, TreeNode b){
	if(a != null && b!= null){
		if(a.val != b.val){
			return false;
		}
		if(a.val == b.val){
			return cmp(a.left, b.right) && cmp(a.right, b.left);
		}
	}else if(a== null && b == null){
		return true;
	}else{
		return false;
	}
}

全部代码如下:

class Solution {
   boolean cmp(TreeNode a, TreeNode b){
	if(a != null && b!= null){
		if(a.val != b.val){
			return false;
		}
		if(a.val == b.val){
			return cmp(a.left, b.right) && cmp(a.right, b.left);
		}
	}else if(a== null && b == null){
		return true;
	}
	return false;
	
}
    public boolean isSymmetric(TreeNode root) {
        if(root == null){
            return true;
        }
        TreeNode left = root.left;
        TreeNode right = root.right;
        return cmp(left, right);
    }
}
非递归怎么写?

之前我说,可能要记录层数才能做到按照某种顺序(如中序)输出,但是这样还不行。我们知道,仅靠中序遍历是不能得到一个树的,可能许多不同的树中序遍历后都是一个顺序。所以只能另想它法。

既然存值不行,那我们就存节点。将节点按照某种顺序存进数组中,再判断两个数组是否是相同值。

class Solution {
  
    public boolean isSymmetric(TreeNode root) {
        Queue<TreeNode> left = new LinkedList<TreeNode>();
        Queue<TreeNode> right = new LinkedList<TreeNode>();

        if(root == null){
            return true;
        }
        if(root.left == null && root.right == null){
            return true;
        }
        if(root.left == null || root.right == null){
            return false;
        }
        if(root.left != null && root.right != null){
            left.offer(root.left);
            right.offer(root.right);
        }
        
        while(!left.isEmpty() && !right.isEmpty()){
            TreeNode l = left.poll();
            TreeNode r = right.poll();

            if(l == null && r == null){
                continue;
            }
            if(l != null && r != null && l.val != r.val){
                return false;
            }
            if(l == null || r == null){
                return false;
            }
            
            left.offer(l.left);
            left.offer(l.right);

            right.offer(r.right);
            right.offer(r.left);
        }
        return true;
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值