【Leetcode刷题】【22/98/226/111/236/105/106】括号生成,验证二叉搜索树,翻转二叉树,二叉树的最小深度,最近公共祖先

22括号生成

在这里插入图片描述
解题思路:2n个格子,每个格子可以存放两种,
限制条件:1.左括号必须在第一个位置,并且左扩号的个数不大于n
2.右括号的个数不大于左括号的个数
3.插入左括号的代码要在右括号之上
4.当左括号个数与右括号个数都等于n时,往结果集里加入字符串,

class Solution {
    private List<String> list;
    public List<String> generateParenthesis(int n) {
       list = new ArrayList<String>();
       generate(0,0,n,"");
       return list;
    }
    public  void generate(int left,int right,int n,String s){
        if(left==n&&right==n){
            list.add(s);
            return;
        }
        if(left<n){
            generate(left+1,right,n,s+"(");
        }
        if(left>right){
            generate(left,right+1,n,s+")");
        }
    }
}

98验证二叉搜索树

在这里插入图片描述
思路:
这里得拒绝人肉递归,可以想到中序遍历的一个性质:就是遍历出来的数是按顺序递增的,所以我们只要在中间检查当前位置值是否小于前一个元素值。

class Solution {
     long lastval=Long.MIN_VALUE;//初始化一个最小值
    public boolean isValidBST(TreeNode root){
        return helper(root);
    }
    public  boolean helper(TreeNode root){
       if(root==null){//根节点为空,则返回true
           return true;
       }
       if(!helper(root.left)){//先遍历左子树
           return false;
       }
       if(root.val<=lastval){//中序遍历一个特征就是遍历的树会从小到大排列,所以如果当前值小于上一个值,则返回false
           return false;
       }
       lastval=(long)root.val;//并将当前值赋给lastval,
       if(!helper(root.right)){//遍历右子树
           return false;
       }
       return true;
    }
}

226翻转二叉树

题目描述

在这里插入图片描述

class Solution {
    public TreeNode invertTree(TreeNode root) {
      if(root==null){
          return null;
      }
      TreeNode right=invertTree(root.right);
      TreeNode left=invertTree(root.left);
      root.left=right;
      root.right=left;
      return root;
      }
}

111二叉树的最小深度

题目描述

在这里插入图片描述
三段代码,时间0ms,这里与最大深度很相似,最大深度是递归查找左右子树的最大深度最后加一,那我们想着最小深度可以求最小深度加一,但其实漏了特殊情况,就是当节点左孩子为空或者右孩子为空的时候,若是按正常取最小值,返回的是0,但题目是到叶子节点,所以应该返回左右子树最大的那个。

class Solution {
    public int minDepth(TreeNode root) {
         if(root==null){
             return 0;
         }
         if(root.left==null||root.right==null){//当节点的左孩子为空或者右孩子为空时,需要返回的是左右子树的最大值,因为是到叶子节点。
             return Math.max(minDepth(root.left),minDepth(root.right))+1;
         }
         return Math.min(minDepth(root.left),minDepth(root.right))+1;
    }
}

236最近公共祖先

题目描述

在这里插入图片描述

思路

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null||root==p||root==q){//节点为空或者节点为p,q则返回
            return root;
        }
        TreeNode left=lowestCommonAncestor(root.left,p,q);
        TreeNode right=lowestCommonAncestor(root.right,p,q);

        if(left==null){//如果左节点为空,说明祖先在root的右子树,返回右子树继续查找
            return right;
        }
        if(right==null){//如果右子树为空,说明祖先在root的左子树,返回左子树继续查找
            return left;
        }
        return root;//如果左,右子树都不为空,说明祖先为root,返回即可
    }
}

105从前序遍历与中序遍历构造二叉树

题目描述

在这里插入图片描述

思路

1.构建二叉树包括三部分:root、左子树、右子树
2.左右子树的构建,又包括 root 和 左右子树
3.题目关键是如何划分左右子树,然后递归构建左右子树

定位出根节点的位置,划分左右子树
1.preorder 的第一项肯定是根节点 —— [ 根 | 左右 ]
2.根据根节点,在 inorder [左 | 根 | 右]中划分出左、右子树的 inorder 序列
3.通过 inorder 中左右子树的 size,在 preorder 中确定左、右子树的 preorder 序列
4.得到左、右子树的 preorder 和 inorder 序列,则传入函数,构建左右子树

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder == null || preorder.length == 0 || inorder == null || inorder.length == 0 || preorder.length != inorder.length) {//前序遍历数组或中序遍历数组为空,返回空
            return null;
        }
        return help(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
    }

    private TreeNode help(int[] preorder, int pStart, int pEnd, int[] inorder, int iStart, int iEnd) {pstart为前序的头结点,pEnd为前序的尾结点
        //递归的第一步:递归终止条件,避免死循环
        if (pStart > pEnd || iStart > iEnd) {//头结点大于尾结点,返回空
            return null;
        }
        //重建根节点
        TreeNode treeNode = new TreeNode(preorder[pStart]);
        int index = 0;  //index找到根节点在中序遍历的位置
        while (inorder[iStart + index] != preorder[pStart]) {
            index++;
        }
        //重建左子树
        treeNode.left = help(preorder, pStart + 1, pStart + index, inorder, iStart, iStart + index - 1);//中序遍历iStart+index为根节点的位置,所以iStart到iStart+index-1为左子树的范围,长度为index-1,则前序遍历中,左子树开始的结点为pStart+1,长度为index-1,所以结束的结点为pStart+1+index-1=pStart+index.
        //重建右子树
        treeNode.right = help(preorder, pStart + index + 1, pEnd, inorder, iStart + index + 1, iEnd);//中序遍历中右子树的开始的结点为iStart+index+1,结束结点为iEnd,所以前序遍历右子树开始的结点为pStart+index+1,结束的结点为pEnd
        return treeNode;

    }


}

106由后序遍历和中序遍历构造二叉树

题目描述

在这里插入图片描述
思路:
1.构建二叉树包括三部分:root、左子树、右子树
2.左右子树的构建,又包括 root 和 左右子树
3.题目关键是如何划分左右子树,然后递归构建左右子树

定位出根节点的位置,划分左右子树
1.postorder 的第一项肯定是根节点 —— [ 左右|根 ]
2.根据根节点,在 inorder [左 | 根 | 右]中划分出左、右子树的 inorder 序列
3.通过 inorder 中左右子树的 size,在 postorder 中确定左、右子树的 preorder 序列
4.得到左、右子树的 postorder 和 inorder 序列,则传入函数,构建左右子树

class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
          if(inorder==null||inorder.length==0||postorder==null||postorder.length==0||inorder.length!=postorder.length){
              return null;
          }
          return helper(inorder,0,inorder.length-1,postorder,0,postorder.length-1);
    }


          public TreeNode helper(int[]inorder,int iStart,int iEnd,int[] postorder,int pStart,int pEnd){
              if(iStart>iEnd||pStart>pEnd){
                  return null;
              }
              TreeNode treenode=new TreeNode(postorder[pEnd]);//重建根节点,后序遍历所有根节点总是在末尾
              int index=0;
              //定位inorder中根节点的位置
              while(inorder[iStart+index]!=postorder[pEnd]){//以此找出中序遍历中根节点的位置
                  index++;
              }
              //重建左子树
              treenode.left=helper(inorder,iStart,iStart+index-1,postorder,pStart,pStart+index-1);//由中序遍历可以知道左子树的范围是iStart到iStart+index-1,长度为index-1,所以后序遍历中左子树开始节点为pStart,末尾节点为pStart+index-1.
              //重建右子树
              treenode.right=helper(inorder,iStart+index+1,iEnd,postorder,pStart+index,pEnd-1);//由中序遍历可知,右子树的开始节点为iStart+inde+1到iEnd,后序遍历的右子树开始节点为pStart+index,末尾节点为pEnd-1.
              return treenode;

          }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱技术的小小林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值