LeetCode Top100之101,102,104,105题

101. 对称二叉树
① 题目描述
  • 给定一个二叉树,检查它是否是镜像对称的。
  • 例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
    在这里插入图片描述
  • 但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
    在这里插入图片描述
  • 说明: 如果你可以运用递归和迭代两种方法解决这个问题,会很加分。
② 递归
  • 最开始,自己想使用中序遍历,如果获得的数组是对称的,那么二叉树对称。发现如果出现下面的类似情况,虽然遍历后为2, 2, 1, 2, 2,但是他不是镜像对称的。
    在这里插入图片描述
  • 所谓的镜像对称,一棵二叉树,围绕根节点,左子树和右子树对称,左子树的左叶子节点和右子树的右叶子节点对称。总结起来就是:原像的左边对应镜子中的右边。
    在这里插入图片描述
  • 比较的是一棵树本身,我们可以比较他的左右子树是否对称;也可以为他传入自身,看是否对称。下面的情况明显不对称:
    在这里插入图片描述
  • 镜像对称,一定是根节点的值相等且左子树的left = 右子树的right且左子树的right = 右子树的left。
  • 传入自身进行比较:

public boolean isSymmetric(TreeNode root) {
    return isMirror(root, root);
}

public boolean isMirror(TreeNode root1, TreeNode root2) {
    if (root1 == null && root2 == null) {
        return true;
    }
    if (root1 == null || root2 == null) {
        return false;
    }
    return (root1.val == root2.val) && isMirror(root1.left, root2.right) &&
            isMirror(root1.right, root2.left);
}
  • 传入左子树和右子树比较:
public boolean isSymmetric(TreeNode root) {
    if(root==null){
        return true;
    }
   return  isMirror(root.left,root.right);
}
public boolean isMirror(TreeNode root1,TreeNode root2){
    if(root1==null&&root2==null){
        return true;
    }
    if(root1==null||root2==null){
        return false;
    }
    return (root1.val==root2.val)&&isMirror(root1.left,root2.right)&&
        isMirror(root1.right,root2.left);
}
③ 迭代
  • 使用队列,队列Queue使用LinkedList实现。
  • 代码如下:
public boolean isSymmetric(TreeNode root) {
    Queue<TreeNode> q = new LinkedList<>();
    q.add(root);
    q.add(root);
    while (!q.isEmpty()) {
        TreeNode t1 = q.poll();
        TreeNode t2 = q.poll();
        if (t1 == null && t2 == null) {
            continue;
        }
        if (t1 == null || t2 == null) {
            return false;
        }
        if (t1.val != t2.val) {
            return false;
        }
        q.add(t1.left);
        q.add(t2.right);
        q.add(t1.right);
        q.add(t2.left);
    }
    return true;
}
102. 二叉树的层次遍历
① 题目描述
  • 给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。
  • 例如: 给定二叉树: [3,9,20,null,null,15,7],

在这里插入图片描述

  • 返回其层次遍历结果:
    在这里插入图片描述
② 迭代
  • 使用队列,每层的节点个数等于队列大小,因此需要弹出size个节点,并且每个List<Integer>添加size个元素,将每个节点的非空的左右节点压入队列。
  • 代码如下:
public List<List<Integer>> levelOrder(TreeNode root) {
    List<List<Integer>> result = new ArrayList<>();
    Queue<TreeNode> queue = new LinkedList<>();
    int level = 0;
    if (root == null) {
        return result;
    }
    queue.add(root);
    while (!queue.isEmpty()) {
        int size = queue.size();
        result.add(new ArrayList<>());
        for (int i = 0; i < size; i++) {
            TreeNode node = queue.poll();
            result.get(level).add(node.val);
            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            }
        }
        level++;
    }
    return result;
}
③ 递归
  • 最简单的解法就是递归,首先确认树非空,然后调用递归函数 helper(node, level),参数是当前节点和节点的层次。程序过程如下:
    ① 输出列表称为 result,当前最高层数就是列表的长度 len(result)。比较访问节点所在的层次 level 和当前最高层次 len(result) 的大小,如果前者更大就向 result 添加一个空列表。
    ② 将当前节点插入到对应层的列表 result[level] 中。
    ③ 递归非空的孩子节点:helper(node.left / node.right, level + 1)。
  • 代码如下:
List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> levelOrder(TreeNode root) {
   if (root == null) {
       return result;
   }
   helper(root, 0);
   return result;
}

public void helper(TreeNode root, int level) {
   if (result.size() == level) {// 需要新建level的list
       result.add(new ArrayList<>());
   }
   result.get(level).add(root.val);
   if (root.left != null) {
       helper(root.left, level + 1);
   }
   if (root.right != null) {
       helper(root.right, level + 1);
   }
}
完全二叉树的判断
  • 完全二叉树的特点:从根节点至整棵树的倒数第二层为一颗满二叉树,最后一层的叶子节点从左往右依次填充。
  • 有两种情况需要返回false
  1. 当前节点有右孩子,却没有左孩子。
  2. 前面的节点已经开启叶子节点验证,要求当前节点不能有左右孩子,即当前节点为叶子节点;开启的时机:节点的右孩子为空。
  • 代码如下,时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)
public boolean isCompleteTree(TreeNode root) {
        boolean check = false; // 用于检测后继节点是否为叶子节点
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            // 有右孩子却没有左孩子,说明该树不是完全二叉树
            if (node.left == null && node.right != null) {
                return false;
            }
            // 开启叶子节点验证,当前节点却不是叶子节点,说明该树不是完全二叉树
            if (check && !(node.left == null && node.right == null)) {
                return false;
            }
            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            } else {// 开启叶子节点验证
                check = true;
            }
        }
        return true;
    }
104. 二叉树的最大深度
① 题目描述
  • 给定一个二叉树,找出其最大深度。
  • 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
  • 说明: 叶子节点是指没有子节点的节点。
  • 示例:

给定二叉树 [3,9,20,null,null,15,7],
返回它的最大深度 3 。
在这里插入图片描述

② 递归
  • 自己的想法:当前节点为null,返回0;否则返回左子树或右子树较大深度 + 1,1是当前节点为一层。
  • 代码如下,超级简单:
public int maxDepth(TreeNode root) {
    if (root == null) {
        return 0;
    }
    return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;

}
③ 迭代
  • 受到102的启发,我们可以通过层次遍历,获得二叉树的层次,就是其最大深度。
  • 使用队列,实现通过迭代进行二叉树的层次遍历:
public int maxDepth(TreeNode root) {
    if (root == null) {
        return 0;
    }
    Queue<TreeNode> queue = new LinkedList<>();
    int level = 0;
    queue.add(root);
    while (!queue.isEmpty()) {
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            TreeNode node = queue.poll();
            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right!=null){
                queue.add(node.right);
            }
        }
        level++;
    }
    return level;
}
105. 从前序与中序遍历序列构造二叉树
① 题目描述
  • 根据一棵树的前序遍历与中序遍历构造二叉树。
  • **注意:**你可以假设树中没有重复的元素。
  • 例如,给出

前序遍历preorder = [3,9,20,15,7]
中序遍历inorder = [9,3,15,20,7]

  • 返回如下的二叉树:
    在这里插入图片描述
② 递归构造
  • 通过观察发现,preorder中的第一个数为根节点,在inorder中找到对应的根节点,整个数组根节点左边为左子树的元素,右边为右子树的元素。例如,15,20,7就是右子树中序元素,20,15,7就是右子树先序元素。
  • 20做根节点,15就是左子树中序元素,7就是右子树中序元素。
  • 我们可以先根据根节点构造一棵二叉树,然后递归构造二叉树左右子树。
  • 其中,如何复制数组中的左子树元素、右子树元素,如果使用for循环太麻烦!于是查找API,决定使用System.arraycopy(src, 0, dst, 0, len);这个函数。
  • 代码如下:
public TreeNode buildTree(int[] preorder, int[] inorder) {
    if (preorder.length == 0 || inorder.length == 0) {
        return null;
    }
    int index = 0;
    for (int i = 0; i < inorder.length; i++) {// 确定中序的根节点下标
        if (inorder[i] == preorder[0]) {
            index = i;
            break;
        }
    }
    TreeNode root = new TreeNode(inorder[index]);
    // 构造左子树的先序和中序数组
    int[] leftInorder = new int[index];
    System.arraycopy(inorder, 0, leftInorder, 0, index);
    int[] leftPreorder = new int[index];
    System.arraycopy(preorder, 1, leftPreorder, 0, index);
    root.left = buildTree(leftPreorder, leftInorder);
    // 构造右子树的先序和中序数组
    int[] rightInorder = new int[inorder.length - index - 1];
    System.arraycopy(inorder, index + 1, rightInorder, 0, rightInorder.length);
    int[] rightPreorder=new int[inorder.length-index-1];
    System.arraycopy(preorder,index+1,rightPreorder,0,rightPreorder.length);
    root.right=buildTree(rightPreorder,rightInorder);
    return root;
}
④ 相似题目—— 106. 从中序与后序遍历序列构造二叉树
  • 抓住一个关键点,后序遍历的末节点是二叉树的根节点。
  • 注意: 后序遍历的右子树数组下标为index开始拷贝。代码如下:
public TreeNode buildTree(int[] inorder, int[] postorder) {
   if (inorder.length == 0 || postorder.length == 0) {
        return null;
    }
    // 确定根节点的index
    int index = 0;
    for (int i = 0; i < inorder.length; i++) {
        if (inorder[i] == postorder[postorder.length - 1]) {
            index = i;
            break;
        }
    }
    TreeNode node = new TreeNode(inorder[index]);
    // 构造左子树的中序和后序数组
    int[] leftInorder = new int[index];
    System.arraycopy(inorder, 0, leftInorder, 0, leftInorder.length);
    int[] leftPostorder = new int[index];
    System.arraycopy(postorder, 0, leftPostorder, 0, leftPostorder.length);
    node.left = buildTree(leftInorder, leftPostorder);
    // 构造右子树的中序和后序数组
    int[] rightInorder = new int[inorder.length - index - 1];
    System.arraycopy(inorder, index + 1, rightInorder,0,rightInorder.length);
    int[] rightPostorder = new int[inorder.length - index - 1];
    System.arraycopy(postorder,index,rightPostorder,0,rightPostorder.length);
    node.right=buildTree(rightInorder,rightPostorder);
    return node;  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值