【剑指offer】面试题28:对称的二叉树

题目:请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。

牛客网链接:https://www.nowcoder.com/questionTerminal/ff05d44dfdb04e1d83bdbdab320efbcb 

如上图所示:第一棵二叉树是对称的,剩下两棵都不是对称的。

通常我们有三种不同的二叉树遍历方法:前序遍历、中序遍历以及后续遍历。在这三种遍历算法中,都是先遍历左子节点再遍历右子节点。我们是否可以定义一种遍历算法,先遍历右子节点在遍历左子节点呢?比如我们针对前序遍历定义一种对称的遍历算法,即先遍历父节点,再遍历它的右子节点,最后遍历它的左子节点。

但是我们需要注意的是上图中第三棵树明显是不对称的,但是如果采用上诉方法,前序遍历和对称前序遍历的结果都为{7,7,7,7,7,7},从结果上来看却是对称的了,要想解决这个问题,我们需要将每个节点的null指针也考虑进去,这样就可以避免这个问题了。

我们发现可以通过比较二叉树的前序遍历和对称前序遍历序列来判断二叉树是不是对称的。如果两个序列是一样的,那么二叉树就是对称的。

思路:首先根节点以及其左右子树,左子树的左子树和右子树的右子树相同、左子树的右子树和右子树的左子树相同即可,采用递归。非递归也可,采用栈或队列存取各级子树根节点。

具体代码实现如下:

public class SymmetricalTree {

	class TreeNode{
		private int val = 0;
		private TreeNode left = null;
		private TreeNode right = null;
		
		public TreeNode(int val){
			this.val = val;
		}
	}
	
	public boolean isSymmetrical(TreeNode root){
		if(root == null){
			return true;
		}
		return isSymmetrical(root.left, root.right);
	}

	private boolean isSymmetrical(TreeNode left, TreeNode right) {
                if(left == null){
			return right == null;
		}
		if(right == null){
			return false;
		}
		if(left.val != right.val){
			return false;
		}
		// 左的右和右的左要相等、左的左和右的右要相等
		return isSymmetrical(left.right, right.left) && 
				isSymmetrical(left.left, right.right);
	}
}

上面采用的是递归的方法实现的,下面再展示下使用非递归(即循环方式)的代码实现:

DFS使用stack来保存成对的节点

1、出栈的时候也是成对成对的 

  • 若都为空,继续;
  • 一个为空,返回false;
  • 不为空,比较当前值,值不等,返回false;

2、确定入栈顺序,每次入栈都是成对成对的,如left.left, right.right ;left.rigth,right.left

public class SymmetricalTree {

	class TreeNode{
		private int val = 0;
		private TreeNode left = null;
		private TreeNode right = null;
		
		public TreeNode(int val){
			this.val = val;
		}
	}
	
	/**
	 * 非递归实现
	 */
	public boolean isSymmetricalDFS(TreeNode root){
		if(root == null){
			return true;
		}
		
		Stack<TreeNode> stack = new Stack<TreeNode>();
		
		stack.push(root.left);
		stack.push(root.right);
		
		while(!stack.isEmpty()){
			// 成对取出
			TreeNode right = stack.pop();
			TreeNode left = stack.pop();
			
			if(left == null && right == null){
				continue;
			}
			if(left == null || right == null){
				return false;
			}
			if(left.val != right.val){
				return false;
			}
			
			// 成对插入
			stack.push(left.left);
			stack.push(right.right); // 左的左和右的右
			
			stack.push(left.right);
			stack.push(right.left);  // 左的右和右的左
		}
		return true;
	}
}

除了使用Stack这种数据结构外,还可以使用Queue实现,代码同上面类似。每次进队和出队都是成对的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值