二叉树的属性

本次来介绍二叉树的属性:

  1. 二叉树是否对称
  2. 二叉树是否相同
  3. 二叉树是否平衡
  4. 是否是二叉搜索树
  5. 二叉树是否存在重复

二叉树相关题目要思考采取遍历模式还是分治模式

一、对称二叉树[重点复习😒]

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;
    }
}

五、寻找重复的子树

分析:

  1. 需要用到子树,很明显应该用后序遍历。
  2. 那么在考虑怎么去判断两个子树是否一样(重复)呢?用相同子树的判断方法么?不现实,先说可不可实现,递归中套递归效率太低。
  3. 可以将二叉树序列化,加入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:寻找重复的子树

环环无敌大可爱😄

posted @ 2022-04-18 15:45  盐小果  阅读(42)  评论(0编辑  收藏  举报