LeetCode初级算法训练-树(完成)

简介

上一篇 : LeetCode初级算法训练-链表

下一篇 : LeetCode初级算法训练-排序和搜索

本来想重初中级和企业面试算法开始的,但是最后还是选择从基础的开始,因为我们并不是为了刷题而刷题,而是在刷题过程中锻炼一种算法思维,在大量的训练之后形成一种对算法的独特见解,培养那种对算法的的敏感度,看到题目,大脑中可以浮现一个解题蓝图,而且从初级开始慢慢建立信心,而且这也是在为后边复杂算法的解题思路打基础。

LeetCode初级算法简介

如果你也想训练自己的算法思维,也可以加入我,从初级算法开始,开启你的算法之旅:初级算法

自己的一些思考:不要在看完题目后直接就看答案,然后去背题,这样行成的算法记忆是不牢固的,一定要有自己的思考;而且不要一开始就在IDEA上边去写,一定试着自己在leetCode提供的白板上边写一遍最后在放到IDEA上边去执行看有什么问题,以便巩固你的基础API的使用和熟练度;还有一点就是大胆些,不是面试我们试错成本低,尽可能把我们的想法融入到代码中

因篇幅问题,博客中只列出示例和自己的解题答案,详细可以直接点击题目查看。

二叉树的最大深度

给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:
给定二叉树 [3,9,20,null,null,15,7],

 	3
   / \
  9  20
    /  \
   15   7

返回它的最大深度 3 。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null) return 0;
        int max = 1;
        int leftMax = maxDepth(root.left);
        int rightMax = maxDepth(root.right);
    
        return max + Math.max(leftMax,rightMax);
    }
}

39 / 39 个通过测试用例
状态:通过
执行用时:0 ms
内存消耗:40 MB

这个用递归就是,当node为null就返回0,不为null默认就是1层,然后继续深入左右两个子节点,哪个大返回哪个,max + (leftMax和rightMax里边最大的),以此类推。

验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

示例 1:
输入:

    2
   / \
  1   3

输出: true

示例 2:
输入:

    5
   / \
  1   4
     / \
    3   6

输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4 。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
   public boolean help(TreeNode root,Integer min,Integer max){
      if(root == null) return true;
        int val = root.val;
        
        //保证了root的左子树的最大值小于root的值并且root的右子树的最小值大于root的值;
        if(min != null && min >= val) return false;//只要root的左子树中有值大于root,就不是BFT;
        if(max != null && max <= val) return false;//只要root的右子树中有值小于root,就不是BFT;
        
        //保证了root的所有左子树和右子树都是BFT;
        if(!help(root.left,min,val)) return false;//在遍历左子树的时候只关心最大值,所以将val赋给max;
        if(!help(root.right,val,max)) return false;//在遍历右子树的时候只关心最小值,所以将val赋给min;
    
        return true;
    }
    public boolean isValidBST(TreeNode root) {
        if(root == null ) return true;
        return help(root,null,null);
    }
 
}

75 / 75 个通过测试用例
状态:通过
执行用时:0 ms
内存消耗:39.7 MB

对称二叉树

给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [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) {
        if(root == null) return true;
        return check(root.left,root.right);
    }
    
    private boolean check(TreeNode p,TreeNode q) {
        if(p == null && q == null) return true;
         if(p == null || q == null) return false;
        return p.val == q.val && check(p.left,q.right) && check(p.right,q.left);
    }
}

195 / 195 个通过测试用例
状态:通过
执行用时:0 ms
内存消耗:37.7 MB

迭代:一对一对不断的加入队列和取出对比。也是左右两个子树的对比。

/**
 * 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) {
        if(root == null) return true;
    
        return check(root.left,root.right);
    }
    
    public boolean check(TreeNode u, TreeNode v) {
        Queue<TreeNode> q = new LinkedList<TreeNode>();
        q.offer(u);
        q.offer(v);
        while (!q.isEmpty()) {
            u = q.poll();
            v = q.poll();
            if (u == null && v == null) {
                continue;
            }
            if ((u == null || v == null) || (u.val != v.val)) {
                return false;
            }

            q.offer(u.left);
            q.offer(v.right);

            q.offer(u.right);
            q.offer(v.left);
        }
        return true;
    }
}

195 / 195 个通过测试用例
状态:通过
执行用时:1 ms
内存消耗:39.3 MB

二叉树的层序遍历

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。

示例:
二叉树:[3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回其层次遍历结果:

[
  [3],
  [9,20],
  [15,7]
]

深度优先

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

    List<List<Integer>> lists = new ArrayList<>();

    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root == null) return lists;
        help(root,0);
        return lists;
    }

    private void help(TreeNode node,int level){
   		//只有列表大小为当前level时新创建一个数组塞进去,这样其他的相同层级就避免多创建
        if(lists.size() == level) {
            lists.add(new ArrayList<Integer>());
        }
        //把node值添加到当前层级数组中
        lists.get(level).add(node.val);
        
		//递归root左侧下一个层级
        if(node.left != null){
            help(node.left,level + 1);
        }
        //递归root右侧侧下一个层级
         if(node.right != null){
             help(node.right,level + 1);
         }
    }
}

34 / 34 个通过测试用例
状态:通过
执行用时:1 ms
内存消耗:40.3 MB

这种深度优先的策略和广度优先理解起来稍微绕一点。

广度优先

public List<List<Integer>> levelOrder(TreeNode root) {
           //思路 二叉树的层序遍历 通用思路为使用 队列,利用队列先进先出特点保存每一行的结点,遍历之后出队
           //时间复杂度 空间复杂度 O(n)
           List<List<Integer>> res = new ArrayList<>();

           if(root == null){
              return res;
           }
           //存储没层结点队列
           Queue<TreeNode> queueNodes = new LinkedList<>();
           //把当前根节点加入队列
           queueNodes.add(root);

           //遍历队列节点
           while(!queueNodes.isEmpty()){
               //获取当前层级有多少个节点
               int count = queueNodes.size();
               //保存当前遍历节点值得 list
               List<Integer> temp = new ArrayList<>();
               //根据队列中的数据 遍历获取节点值
               for (int i = 0; i < count; i++) {
                   //当前节点是否有左右子节点
                   if(queueNodes.peek().left !=null){
                     queueNodes.offer(queueNodes.peek().left);
                   }
                   if(queueNodes.peek().right !=null){
                    queueNodes.offer(queueNodes.peek().right);
                  }
                  //保存当前节点行元素值数组 并从队列中删除
                  temp.add(queueNodes.poll().val);
               }
               //保存每一层节点数组
               res.add(temp);
           }

            return res;
    }
}
将有序数组转换为二叉搜索树

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

给定有序数组: [-10,-3,0,5,9],

一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5

刚开始思路是对的,但是对于找位置找边界没有找对。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return  help(nums,0,nums.length - 1);
    }

    private TreeNode help(int[] nums,int left,int right){
        
        if(left > right) return null;

        int mid = (left + right)/2;

        TreeNode root = new TreeNode(nums[mid]);

        root.left = help(nums,left,mid - 1);
        root.right = help(nums,mid + 1, right);
        return root;
    }
}

32 / 32 个通过测试用例
状态:通过
执行用时:0 ms
内存消耗:39.6 MB

猜你喜欢

转载自blog.csdn.net/u011148116/article/details/107212165