二叉树的属性
本次来介绍二叉树的属性:
- 二叉树是否对称
- 二叉树是否相同
- 二叉树是否平衡
- 是否是二叉搜索树
- 二叉树是否存在重复
二叉树相关题目要思考采取遍历模式
还是分治模式
。
一、对称二叉树[重点复习
😒]
1. 遍历模式
- 迭代法
该问题的难点在于入队的顺序以及碰到空节点时怎么处理。
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
if(root.left == null && root.right == null) return true;
LinkedList<TreeNode> queue = new LinkedList<>();
queue.offer(root.left);
queue.offer(root.right);
while(!queue.isEmpty()) {
TreeNode left = queue.poll();
TreeNode right = queue.poll();
if(left == null && right == null) {
continue;//对称节点都为null,则不做判断,跳过次次循环。
}
if(left == null || right == null || left.val != right.val) {
return false;
}
//按照对称节点入队
queue.offer(left.left);
queue.offer(right.right);
queue.offer(left.right);
queue.offer(right.left);
}
return true;
}
}
2. 分治模式
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
return check(root.left,root.right);
}
boolean check(TreeNode left, TreeNode right) {
if(left == null && right != null) return false;
if(left != null && right == null) return false;
if(left == null && right == null) return true;
if(left.val != right.val) return false;
//检查对称节点
return check(left.left,right.right) && check(left.right,right.left);
}
}
二、相同的树
1. 分治模式
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null && q == null) return true;
if(p == null || q == null || p.val != q.val) return false;
return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
}
}
2. 拓展
判断一颗二叉树是否是另一棵二叉树的子树。
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
//两棵树都为空
if(root == null) {
return subRoot == null;
}
if(isSame(root,subRoot)) {//两棵树相同
return true;
}
//subRoot是否是root的子树
return isSubtree(root.left,subRoot) || isSubtree(root.right,subRoot);
}
//判断两棵树是否相同
boolean isSame(TreeNode p, TreeNode q) {
if(p == null && q == null) return true;
if(p == null || q == null || p.val != q.val) return false;
return isSame(p.left,q.left) && isSame(p.right,q.right);
}
}
三、平衡二叉树
平衡二叉树的定义:一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1。
1. 分治模式
class Solution {
boolean balance = true;
public boolean isBalanced(TreeNode root) {
if(root == null) return true;
depth(root);
return balance;
}
//求最大深度的代码
int depth(TreeNode root) {
if(root == null) return 0;
int left = depth(root.left);
int right = depth(root.right);
//在后序位置添加平衡二叉树判断代码
if(Math.abs(left-right) > 1) {
balance = false;
}
return 1 + Math.max(left,right);
}
}
四、验证二叉搜索树
二叉搜索树:左小右大,按照中序遍历是升序(严格升序),在中序遍历中交换左右子树顺序便是降序。
1. 遍历模式
- 递归法
此方法效率较低,如何在递归中判断二叉树是否递增呢?
class Solution {
LinkedList<Integer> list = new LinkedList<>();
public boolean isValidBST(TreeNode root) {
traverse(root);
//判断list是否是递增
for(int i=0; i<list.size()-1; i++) {
if(list.get(i) >= list.get(i+1)) {
return false;
}
}
return true;
}
//中序遍历并记录节点值
void traverse(TreeNode root) {
if(root == null) return;
traverse(root.left);
list.add(root.val);
traverse(root.right);
}
}
在递归函数中添加判断
class Solution {
long pre = Long.MIN_VALUE;
boolean isIncre = true;
public boolean isValidBST(TreeNode root) {
traverse(root);
return isIncre;
}
//中序遍历并判断是否递增
void traverse(TreeNode root) {
if(root == null) return;
traverse(root.left);
if(root.val <= pre) {//严格升序,等于也不行
isIncre = false;
}
pre = root.val;
traverse(root.right);
}
}
- 迭代法
class Solution {
public boolean isValidBST(TreeNode root) {
if(root == null) return true;
LinkedList<TreeNode> stack = new LinkedList<>();
TreeNode curNode = root;
long pre = Long.MIN_VALUE;
while(curNode != null || stack.isEmpty()) {
//遍历左子树
while(curNode != null) {
stack.push(curNode);
curNode = curNode.left;
}
//中序代码位置,加入判断条件
curNode = stack.pop();
//严格升序,等于也不行
if(curNode.val <= pre) return false;
pre = curNode.val;
//遍历右子树
curNode = curNode.right;
}
return true;
}
}
五、寻找重复的子树
分析:
- 需要用到子树,很明显应该用后序遍历。
- 那么在考虑怎么去判断两个子树是否一样(重复)呢?用相同子树的判断方法么?不现实,先说可不可实现,递归中套递归效率太低。
- 可以将二叉树序列化,加入map集合中,如果次数大于1,不就说明重复了。
class Solution {
Map<String,Integer> map = new HashMap<>();
LinkedList<TreeNode> res = new LinkedList<>();
public List<TreeNode> findDuplicateSubtrees(TreeNode root) {
traverse(root);
return res;
}
String traverse(TreeNode root) {
if(root == null) return "#";
String left = traverse(root.left);
String right = traverse(root.right);
String subTree = left + "," + right + "," + root.val;
int freq = map.getOrDefault(subTree,0);
//很巧妙,头一次都是0,第二次出现才是1,第三次是2,但是就不要了
if(freq == 1) {
res.add(root);
}
map.put(subTree,freq+1);
return subTree;
}
}
题目链接
leetcode-101:对称二叉树
leetcode-100:相同的树
leetcode-572:另一棵树的子树
leetcode-110:平衡二叉树
leetcode-98:验证二叉搜索树
leetcode-652:寻找重复的子树
环环无敌大可爱
😄