二叉树相关算法题解

二叉树

94. 二叉树的中序遍历

难度中等483

给定一个二叉树,返回它的中序 遍历。

示例:

输入: [1,null,2,3]
   1
    \
     2
    /
   3

输出: [1,3,2]

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

递归解答:

class Solution {

    //保存结果
    List<Integer> result=new ArrayList<>();

    public List<Integer> inorderTraversal(TreeNode root) {
        if(root!=null){
            inorderTraversal(root.left);
            result.add(root.val);
            inorderTraversal(root.right);
        }
        return result;
    }
}

迭代解答:

class Solution {

    //保存结果
    List<Integer> result=new ArrayList<>();

    public List<Integer> inorderTraversal(TreeNode root) {
        if(root!=null){
            Stack<TreeNode> stack=new Stack<>();
            while(!stack.empty()||root!=null){
                if(root!=null){
                    stack.push(root);
                    root=root.left;
                }else{
                    TreeNode pop=stack.pop();
                    result.add(pop.val);
                    root=pop.right;
                }
            }
        }
        return result;
    }
}

95. 不同的二叉搜索树 II

给定一个整数 n,生成所有由 1 … n 为节点所组成的二叉搜索树

示例:

输入: 3
输出:
[
  [1,null,3,2],
  [3,2,null,1],
  [3,1,null,null,2],
  [2,1,3],
  [1,null,2,null,3]
]
解释:
以上的输出对应以下 5 种不同结构的二叉搜索树:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

解答:

class Solution {

    public List<TreeNode> generateTrees(int n) {
        if(n==0)
            return new ArrayList<TreeNode>();
        return createTree(1,n);
    }

    //生成范围start~end的二叉搜索树
    public List<TreeNode> createTree(int start,int end){
        //保存结果集
        List<TreeNode> result=new ArrayList<>();
        //不存在要添加一个null节点,不能省略,否则其中一个集合空,foreach遍历时无法组合
        if(start>end){
            result.add(null);
            return result;
        }
        //以i为根节点生成二叉搜索树
        for(int i=start;i<=end;i++){
            //i的不同左子树集合
            List<TreeNode> treeListL=createTree(start,i-1);
            //i的不同右子树集合
            List<TreeNode> treeListR=createTree(i+1,end);
            //全组合
            for(TreeNode treeL:treeListL){
                for(TreeNode treeR:treeListR){
                    TreeNode node=new TreeNode(i);
                    node.left=treeL;
                    node.right=treeR;
                    result.add(node);
                }
            }
        }
        return result;
    }

}

96. 不同的二叉搜索树

给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?

示例:

输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

解答:

    public int numTrees(int n) {
        //假设dp(N)为以1,2...N为节点组成的二叉搜索树数量
        //f(x)为以x为根节点的二叉搜索树数量
        //那么dp(N)=f(1)+f(2)+...+f(N)
        //f(x)=dp(x-1)*dp(N-x),因为x左边有x-1个节点,右边有N-x个节点
        //因此dp(N)=dp(0)*dp(N-1)+dp(1)*dp(N-2)+....+dp(N-1)*dp(0)
        int[] dp=new int[n+1];
        //初始化
        dp[0]=1;
        dp[1]=1;
        //动态规划更新
        for(int N=2;N<=n;N++){
            for(int x=1;x<=N;x++){
                dp[N]+=dp[x-1]*dp[N-x];
            }
        }
        return dp[n];
    }

98. 验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:

  • 节点的左子树只包含小于当前节点的数。
  • 节点的右子树只包含大于当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

示例 1:

输入:
    2
   / \
  1   3
输出: true

解答:

class Solution {

    //前驱节点
    TreeNode pre=null;
    //是否为二叉搜索树,默认true
    boolean flag=true;

    public boolean isValidBST(TreeNode root) {
        if(root==null)
            return true;
        inorder(root);
        return flag;
    }

    public void inorder(TreeNode root){
        if(root!=null){
            inorder(root.left);
            if(pre!=null){
                //二叉搜索树中序排列是升序,如果小于等于说明不符合
                if(root.val<=pre.val){
                    flag=false;
                    return;
                }
            }
            //更新前驱节点
            pre=root;
            inorder(root.right);
        }
    }

}

100. 相同的树

给定两个二叉树,编写一个函数来检验它们是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例 1:

输入:       1         1
          / \       / \
         2   3     2   3

        [1,2,3],   [1,2,3]

输出: true

示例 2:

输入:      1          1
          /           \
         2             2

        [1,2],     [1,null,2]

输出: false

解答:

	public boolean isSameTree(TreeNode p, TreeNode q) {
        //两个树都为空则代表相同
        if(p==null&&q==null)
            return true;
        //一个为空,一个不为空代表不同
        if((p==null&&q!=null)||(p!=null&&q==null))
            return false;
        //如果值不相同则代表不同,值相同再分别比较左子树和右子树
        if(p.val!=q.val)
            return false;
        return isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
    }

101. 对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

例如,二叉树 [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

进阶:

你可以运用递归和迭代两种方法解决这个问题吗?

递归解答:

    public boolean isSymmetric(TreeNode root) {
        //空树肯定对称
        if(root==null)
            return true;
        //判断左右子树是否对称
        return isMirror(root.left,root.right);
    }

    public boolean isMirror(TreeNode p,TreeNode q) {
        //两个树都为空则代表相同
        if(p==null&&q==null)
            return true;
        //一个为空,一个不为空代表不同
        if((p==null&&q!=null)||(p!=null&&q==null))
            return false;
        //如果值不相同则代表不同,值相同再对称比较p左q右/p右q左
        if(p.val!=q.val)
            return false;
        return isMirror(p.left,q.right)&&isMirror(p.right,q.left);
    }

迭代解答:

    public boolean isSymmetric(TreeNode root) {
        //空树对称
        if(root==null)
            return true;
        //根节点没有左右子树,是对称的
        if(root.left==null&&root.right==null)
            return true;
        //根节点左右子树只有一边,不对称
        if((root.left!=null&&root.right==null)||(root.left==null&&root.right!=null))
            return false;
        //两个栈,s1保存左子树,s2保存右子树
        Stack<TreeNode> s1=new Stack<>();
        Stack<TreeNode> s2=new Stack<>();
        //左右子树的根节点入栈
        s1.push(root.left);
        s2.push(root.right);
        while(!s1.isEmpty()&&!s2.isEmpty()){
            TreeNode pop1=s1.pop();
            TreeNode pop2=s2.pop();
            //节点值不同不对称
            if(pop1.val!=pop2.val)
                return false;
            //一边节点有子树,对应的另一边没有则不对称,否则将对应子树入栈
            if((pop1.left!=null&&pop2.right==null)||(pop1.left==null&&pop2.right!=null))
                return false;
            if(pop1.left!=null&&pop2.right!=null){
                s1.push(pop1.left);
                s2.push(pop2.right);
            }
            if((pop1.right!=null&&pop2.left==null)||(pop1.right==null&&pop2.left!=null))
                return false;
            if(pop1.right!=null&&pop2.left!=null){
                s1.push(pop1.right);
                s2.push(pop2.left);
            }
        }
        //两个栈同时为空说明全部匹配成功
        return s1.isEmpty()&&s2.isEmpty();
    }

102. 二叉树的层序遍历

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

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

    3
   / \
  9  20
    /  \
   15   7

返回其层次遍历结果:

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

解答:

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        //保存结果集
        List<List<Integer>> result=new ArrayList<>();
        //保存节点
        List<TreeNode> trees=new ArrayList<>();
        //保存临时结果
        List<Integer> temp;
        if(root!=null){
            trees.add(root);
            while(!trees.isEmpty()){
                //计算当前层节点数,按数量全部出队,再将其左右节点依次入队
                int n=trees.size();
                temp=new ArrayList<>();
                for(int i=0;i<n;i++){
                    TreeNode remove=trees.remove(0);
                    temp.add(remove.val);
                    //出队节点的左右节点不为空就入队
                    if(remove.left!=null)
                        trees.add(remove.left);
                    if(remove.right!=null)
                        trees.add(remove.right);
                }
                //添加到结果集
                result.add(temp);
            }
        }
        return result;
    }
}

103. 二叉树的锯齿形层次遍历

给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

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

    3
   / \
  9  20
    /  \
   15   7

返回锯齿形层次遍历如下:

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

解答:

    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        //相比102题只需要添加一个boolean变量
        List<List<Integer>> result=new ArrayList<>();
        List<TreeNode> trees=new ArrayList<>();
        List<Integer> temp;
        //控制顺序,是否从左到右
        boolean leftToRight=true;
        if(root!=null){
            trees.add(root);
            while(!trees.isEmpty()){
                int n=trees.size();
                temp=new ArrayList<>();
                for(int i=0;i<n;i++){
                    TreeNode remove=trees.remove(0);
                    temp.add(remove.val);
                    if(remove.left!=null)
                        trees.add(remove.left);
                    if(remove.right!=null)
                        trees.add(remove.right);
                }
                //如果是从右往左要逆序
                if(!leftToRight)
                    Collections.reverse(temp);
                result.add(temp);
                leftToRight=!leftToRight;
            }
        }
        return result;
    }

104. 二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

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

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

    3
   / \
  9  20
    /  \
   15   7

返回它的最大深度 3 。

解答:

    public int maxDepth(TreeNode root) {
        //空树高度为0
        if(root==null)
            return 0;
        //左子树高度
        int hL=maxDepth(root.left);
        //右子树高度
        int hR=maxDepth(root.right);
        //返回左右子树的最大高度加上自己的高度1
        return Math.max(hL,hR)+1;
    }

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

难度中等426

根据一棵树的前序遍历与中序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。

例如,给出

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

返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

解答:

class Solution {

    //存储中序信息,key是节点数值,value是索引
    HashMap<Integer,Integer> map=new HashMap<>();
    //存储前序数组的引用
    int[] pre;

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if(preorder==null||preorder.length==0)
            return null;
        pre=preorder;
        //将中序信息存入map集合
        for(int i=0;i<inorder.length;i++){
            map.put(inorder[i],i);
        }
        return build(0,0,inorder.length-1);
    }

    //从前序遍历中获得当前节点,从中序遍历获得其左右节点
    public TreeNode build(int preIndex,int inStart,int inEnd){
        //临界条件
        if(inStart>inEnd)
            return null;
        //获取先序遍历的节点以及其在中序遍历中的位置
        int val=pre[preIndex];
        int inIndex=map.get(val);
        //构建根节点
        TreeNode cur=new TreeNode(val);
        //左子树数量
        int left=inIndex-inStart;
        //递归构建左右子树
        cur.left=build(preIndex+1,inStart,inIndex-1);//前序遍历中当前节点下一个就是左子树节点
        cur.right=build(preIndex+1+left,inIndex+1,inEnd);//前序中右子树的根节点索引要跳过中序左子树节点的数量
        return cur;
    }

}

106. 从中序与后序遍历序列构造二叉树

根据一棵树的中序遍历与后序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。

例如,给出

中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]

返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

解答:

class Solution {

    //存储中序信息,key是节点数值,value是索引
    HashMap<Integer,Integer> map=new HashMap<>();
    //存储后序数组的引用
    int[] post;

    public TreeNode buildTree(int[] inorder, int[] postorder) {
        if(postorder==null||postorder.length==0)
            return null;
        post=postorder;
        //将中序信息存入map集合
        for(int i=0;i<inorder.length;i++){
            map.put(inorder[i],i);
        }
        return build(post.length-1,0,inorder.length-1);
    }

    //从后序遍历中获得当前节点,从中序遍历获得其左右节点
    public TreeNode build(int postIndex,int inStart,int inEnd){
        //临界条件
        if(inStart>inEnd)
            return null;
        //获取后序遍历的节点以及其在中序遍历中的位置
        int val=post[postIndex];
        int inIndex=map.get(val);
        //构建根节点
        TreeNode cur=new TreeNode(val);
        //右子树数量
        int right=inEnd-inIndex;
        //递归构建左右子树
        cur.left=build(postIndex-1-right,inStart,inIndex-1);//后序遍历中当前节点前一个就是右子树节点
        cur.right=build(postIndex-1,inIndex+1,inEnd);//后序中左子树的根节点索引要跳过中序右子树节点的数量
        return cur;
    }
}

107. 二叉树的层次遍历 II

给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

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

    3
   / \
  9  20
    /  \
   15   7

返回其自底向上的层次遍历为:

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

解答:

	public List<List<Integer>> levelOrderBottom(TreeNode root) {
        //保存结果集
        LinkedList<List<Integer>> result=new LinkedList<>();
        //保存节点
        List<TreeNode> trees=new LinkedList<>();
        //保存临时结果
        List<Integer> temp;
        if(root!=null){
            trees.add(root);
            while(!trees.isEmpty()){
                //计算当前层节点数,按数量全部出队,再将其左右节点依次入队
                int n=trees.size();
                temp=new LinkedList<>();
                for(int i=0;i<n;i++){
                    TreeNode remove=trees.remove(0);
                    temp.add(remove.val);
                    //出队节点的左右节点不为空就入队
                    if(remove.left!=null)
                        trees.add(remove.left);
                    if(remove.right!=null)
                        trees.add(remove.right);
                }
                //自底向上遍历,将自顶向下的结果反向入队即可
                result.addFirst(temp);
            }
        }
        return result;
    }

108. 将有序数组转换为二叉搜索树

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

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

示例:

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

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

      0
     / \
   -3   9
   /   /
 -10  5

解答:

    public TreeNode sortedArrayToBST(int[] nums) {
        if(nums.length==0)
            return null;
        return insert(nums,0,nums.length-1);
    }

    public TreeNode insert(int[] nums,int left,int right){
        //递归停止条件
        if(left>right)
            return null;
        //将中间节点作为根节点
        int mid=(left+right)/2;
        TreeNode root=new TreeNode(nums[mid]);
        //中间节点左边作为左子树,因为是升序数组,左边肯定值更小
        root.left=insert(nums,left,mid-1);
        //中间节点右边作为右子树
        root.right=insert(nums,mid+1,right);
        return root;
    }

110. 平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

示例 1:

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

    3
   / \
  9  20
    /  \
   15   7

返回 true

解答:

    public boolean isBalanced(TreeNode root) {
        //空树是平衡二叉树
        if(root==null)
            return true;
        //左右子树的高度差超过1
        if(Math.abs(depth(root.left)-depth(root.right))>1)
            return false;
        //判断左右子树
        return isBalanced(root.left)&&isBalanced(root.right);
    }

    //求当前节点高度
    public int depth(TreeNode root) {
        if(root==null)
            return 0;
        int hL=depth(root.left);
        int hR=depth(root.right);
        return Math.max(hL,hR)+1;
    }

111. 二叉树的最小深度

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

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

示例:

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

    3
   / \
  9  20
    /  \
   15   7

返回它的最小深度 2.

解答:

	public int minDepth(TreeNode root) {
        //空节点高度0
        if(root==null)
            return 0;
        //没有左右节点高度1
        if(root.left==null&&root.right==null)
            return 1;
        int hL=minDepth(root.left);
        int hR=minDepth(root.right);
        //没有左节点,高度为右节点,反之
        if(hL==0)
            return hR+1;
        if(hR==0)
            return hL+1;
        //左右节点都不为空,返回最小值加上自己的高度1
        return Math.min(hL,hR)+1;
    }

112. 路径总和

给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

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

示例:
给定如下二叉树,以及目标和 sum = 22

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \      \
        7    2      1

返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2

解答:

    public boolean hasPathSum(TreeNode root, int sum) {
        //当前节点为空,寻找失败
        if(root==null)
            return false;
        //当前节点为叶子节点并且值和目标相等,寻找成功
        if(root.val==sum&&root.left==null&&root.right==null)
            return true;
        //在左右子树寻找
        return hasPathSum(root.left,sum-root.val)||hasPathSum(root.right,sum-root.val);
    }

113. 路径总和 II

难度中等213

给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。

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

示例:
给定如下二叉树,以及目标和 sum = 22

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1

返回:

[
   [5,4,11,2],
   [5,8,4,5]
]

解答:

class Solution {

    //保存结果
    List<List<Integer>> result=new ArrayList<>();

    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        path(root,sum,new ArrayList<>());
        return result;
    }

    public void path(TreeNode root,int sum,List<Integer> list){
        if(root!=null){
            list.add(root.val);
            //如果是叶子节点且值和sum相等,说明找到了
            if(root.val==sum&&root.left==null&&root.right==null){
                result.add(new ArrayList<>(list));
                list.remove(list.size()-1);
            }else{
                //在左子树和右子树分别继续查找
                path(root.left,sum-root.val,list);
                path(root.right,sum-root.val,list);
                //查完后要移除末尾元素,回退之前的状态,进行新的查找
                list.remove(list.size()-1);
           }
        }
    }
}

114. 二叉树展开为链表

给定一个二叉树,原地将它展开为链表。

例如,给定二叉树

    1
   / \
  2   5
 / \   \
3   4   6

将其展开为:

1
 \
  2
   \
    3
     \
      4
       \
        5
         \
          6

解答:


116. 填充每个节点的下一个右侧节点指针

给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。初始状态下,所有 next 指针都被设置为 NULL

示例:

img

解答:

    public Node connect(Node root) {
        if(root!=null){
            //如果还有下一层(只需要判断左右节点的一个,因为是完美二叉树)
            if(root.left!=null){
                //连接同一个父节点的两个节点
                root.left.next=root.right;
                //连接不同父节点的两个节点
                if(root.next!=null)
                    root.right.next=root.next.left;
            }
            connect(root.left);
            connect(root.right);
        }
        return root;
    }

117. 填充每个节点的下一个右侧节点指针 II

给定一个二叉树

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。初始状态下,所有 next 指针都被设置为 NULL

示例:

img
输入:root = [1,2,3,4,5,null,7]
输出:[1,#,2,3,#,4,5,7,#]
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。

解答:

    public Node connect(Node root) {
        //使用队列进行层序遍历,依次处理节点
        Deque<Node> trees=new ArrayDeque<>();
        if(root!=null){
            trees.add(root);
            while(!trees.isEmpty()){
                int n=trees.size();
                for(int i=0;i<n;i++){
                    Node remove=trees.removeFirst();
                    help(remove);
                    if(remove.left!=null)
                        trees.add(remove.left);
                    if(remove.right!=null)
                        trees.add(remove.right);
                }
            }
        }
        return root;
    }

    public void help(Node root){
        if(root!=null){
            if(root.left!=null&&root.right!=null)
                root.left.next=root.right;
            if(root.left!=null||root.right!=null) {
                //保存当前节点的next节点、左右节点引用,使代码简洁一点
                Node node=root.next;
                Node rL=root.left;
                Node rR=root.right;
                //只要存在next节点
                while (node != null) {
                    if (rR != null) {//当前节点优先连接右节点
                        if (node.left != null) {//next节点优先连接左节点
                            rR.next = node.left;
                            break;
                        } else if (node.right != null) {//next节点没有左节点,判断右节点
                            rR.next = node.right;
                            break;
                        }
                    }
                    //当前节点没有右节点,判断左节点
                    if (node.left != null) {//next节点优先连接左节点
                        rL.next = node.left;
                        break;
                    } else if (node.right != null) {//next节点没有左节点,判断右节点
                        rL.next = node.right;
                        break;
                    }
                    node = node.next;
                }
            }
        }
    }

129. 求根到叶子节点数字之和

给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。

例如,从根到叶子节点路径 1->2->3 代表数字 123

计算从根到叶子节点生成的所有数字之和。

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

示例 1:

输入: [1,2,3]
    1
   / \
  2   3
输出: 25
解释:
从根到叶子节点路径 1->2 代表数字 12.
从根到叶子节点路径 1->3 代表数字 13.
因此,数字总和 = 12 + 13 = 25.

解答:

class Solution {
    //保存结果
    int sum=0;

    //类似257题
    public int sumNumbers(TreeNode root) {
        search(root,0);
        return sum;
    }
    
    //辅助函数
    public void search(TreeNode root,int n){
        if(root!=null){
            int num=n*10+root.val;
            if(root.left==null&&root.right==null) {
                //到达叶子节点,拼接完值就添加到结果集
                sum+=num;
            }else {
                //还没到叶子节点
                search(root.left, num);
                search(root.right, num);
            }
        }
    }
}


144. 二叉树的前序遍历

给定一个二叉树,返回它的 前序 遍历。

示例:

输入: [1,null,2,3]  
   1
    \
     2
    /
   3 

输出: [1,2,3]

解答:

class Solution {

    //保存结果
    List<Integer> result=new ArrayList<>();

    //递归很简单,直接使用迭代算法
    public List<Integer> preorderTraversal(TreeNode root) {
        if(root!=null){
            Stack<TreeNode> stack=new Stack<>();
            while(!stack.empty()||root!=null){
                if(root!=null){
                    result.add(root.val);
                    stack.push(root);
                    root=root.left;
                }else{
                    TreeNode pop=stack.pop();
                    root=pop.right;
                }
            }
        }
        return result;
    }

}

145. 二叉树的后序遍历

给定一个二叉树,返回它的 后序 遍历。

示例:

输入: [1,null,2,3]  
   1
    \
     2
    /
   3 

输出: [3,2,1]

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

解答:

    //类似二叉树先序遍历,只是利用队列将结果逆序
    public List<Integer> postorderTraversal(TreeNode root) {
        LinkedList<Integer> result=new LinkedList<>();
        if(root!=null){
            Stack<TreeNode> stack=new Stack<>();
            while(!stack.empty()||root!=null){
                if(root!=null){
                    result.addFirst(root.val);
                    stack.push(root);
                    root=root.right;
                }else{
                    TreeNode pop=stack.pop();
                    root=pop.left;
                }
            }
        }
        return result;
    }

156. 上下翻转二叉树

给定一个二叉树,其中所有的右节点要么是具有兄弟节点(拥有相同父节点的左节点)的叶节点,要么为空,将此二叉树上下翻转并将它变成一棵树, 原来的右节点将转换成左叶节点。返回新的根。

例子:

输入: [1,2,3,4,5]

    1
   / \
  2   3
 / \
4   5

输出: 返回二叉树的根 [4,5,2,#,#,3,1]

   4
  / \
 5   2
    / \
   3   1  

解答:

    public TreeNode upsideDownBinaryTree(TreeNode root) {
        //root是空直接返回
        if(root==null)
            return root;
        if(root!=null){
            //左节点为空说明到了叶子节点,直接返回
            if(root.left==null)
                return root;
            //否则新节点是对左节点翻转的结果
            TreeNode newRoot=upsideDownBinaryTree(root.left);
            //找到新节点的最右子结点
            TreeNode n=newRoot;
            while(n.right!=null)
                n=n.right;
            //原节点的右节点作为新节点的左节点
            n.left=root.right;
            //原节点作为新节点的右节点
            n.right=new TreeNode(root.val);
            return newRoot;
        }
        return root;
    }

173. 二叉搜索树迭代器

实现一个二叉搜索树迭代器。你将使用二叉搜索树的根节点初始化迭代器。

调用 next() 将返回二叉搜索树中的下一个最小的数。

示例:

img

BSTIterator iterator = new BSTIterator(root);
iterator.next();    // 返回 3
iterator.next();    // 返回 7
iterator.hasNext(); // 返回 true
iterator.next();    // 返回 9
iterator.hasNext(); // 返回 true
iterator.next();    // 返回 15
iterator.hasNext(); // 返回 true
iterator.next();    // 返回 20
iterator.hasNext(); // 返回 false

解答:

class BSTIterator {

    List<Integer> list=new ArrayList<>();
    int[] arr=null;
    int index=0;

    public BSTIterator(TreeNode root) {
        inorder(root);
        arr=new int[list.size()];
        for(int i=0;i<arr.length;i++)
            arr[i]=list.get(i);
    }
    
    public int next() {
        return arr[index++];
    }
    
    public boolean hasNext() {
        return index<arr.length;
    }

    //中序遍历保存升序序列
    public void inorder(TreeNode root){
        if(root!=null){
            inorder(root.left);
            list.add(root.val);
            inorder(root.right);
        }
    }
}

199. 二叉树的右视图

给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

示例:

输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:

   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---

解答:

class Solution {

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

    public List<Integer> rightSideView(TreeNode root) {
        //初始结果集大小0,所以深度也该设为0
        dfs(root,0);
        return result;
    }

    //使用根-右-左的顺序进行深度优先遍历
    public void dfs(TreeNode root,int depth){
        if(root!=null){
            //根据深度和当前结果集大小判断是否是第一次访问,即该层最右节点
            if(depth==result.size())
                result.add(root.val);
            dfs(root.right,depth+1);
            dfs(root.left,depth+1);
        }
    }
}

222. 完全二叉树的节点个数

给出一个完全二叉树,求出该树的节点个数。

解答:

    public int countNodes(TreeNode root) {
        //空树节点0
        if(root==null)
            return 0;
        //没有左子树肯定也没有右子树
        if(root.left==null)
            return 1;
        //左右子树节点+1
        return 1+countNodes(root.left)+countNodes(root.right);
    }

226. 翻转二叉树

翻转一棵二叉树。

示例:

输入:

     4
   /   \
  2     7
 / \   / \
1   3 6   9

输出:

     4
   /   \
  7     2
 / \   / \
9   6 3   1

解答:

    public TreeNode invertTree(TreeNode root) {
        if(root!=null){
            //翻转左子树赋值给当前节点的右节点,反之
            TreeNode newLeft=invertTree(root.right);
            TreeNode newRight=invertTree(root.left);
            root.left=newLeft;
            root.right=newRight;
        }
        return root;
    }

230. 二叉搜索树中第K小的元素

给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。

说明:
你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。

示例 1:

输入: root = [3,1,4,null,2], k = 1
   3
  / \
 1   4
  \
   2
输出: 1

解答:

class Solution {

    //定义一个计数器
    int count=0;
    //保存结果
    int num=0;

    public int kthSmallest(TreeNode root, int k) {
        count=k;
        help(root);
        return num;
    }

    //按中序遍历搜索,第k个值就是第k小
    public void help(TreeNode root){
        if(root!=null){
            help(root.left);
            count--;
            if(count==0){
                num=root.val;
                return;
            }
            help(root.right);
        }
    }
}

235. 二叉搜索树的最近公共祖先

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X65GZ12A-1588937561384)(https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2018/12/14/binarysearchtree_improved.png)]

示例 1:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6 
解释: 节点 2 和节点 8 的最近公共祖先是 6。

解答:

	public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //p、q的值都小于root,在左子树寻找
        if(root.val>p.val&&root.val>q.val)
            return lowestCommonAncestor(root.left,p,q);
        //p、q的值都大于root,在右子树寻找
        if(root.val<p.val&&root.val<q.val)
            return lowestCommonAncestor(root.right,p,q);
        //不是左右子树,只能是根节点
        return root;
    }

236. 二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KYT66fwZ-1588937561386)(https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2018/12/15/binarytree.png)]

示例 1:

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。

解答:

class Solution {
    //保存结果
    TreeNode res;

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        canFind(root,p,q);
        return res;
    }

    //以当前节点为根搜索,能否找到p,q中的一个
    public boolean canFind(TreeNode root,TreeNode p,TreeNode q){
        if(root==null)
            return false;
        int sum=0;
        //判断当前节点
        sum+=(root==p||root==q)?1:0;
        //判断左子树能否找到
        sum+=canFind(root.left,p,q)?1:0;
        //判断右子树能否找到
        sum+=canFind(root.right,p,q)?1:0;
        //如果sum==2,说明p和q都找到了
        if(sum==2)
            res=root;
        //sum不为0,说明能找到其中一个
        return sum>0;
    }

}

250. 统计同值子树

给定一个二叉树,统计该二叉树数值相同的子树个数。

同值子树是指该子树的所有节点都拥有相同的数值。

示例:

输入: root = [5,1,5,5,5,null,5]

              5
             / \
            1   5
           / \   \
          5   5   5

输出: 4

解答:

class Solution {

    //保存同值子树总和
    int sum=0;

    public int countUnivalSubtrees(TreeNode root) {
        isSub(root);
        return sum;
    }

    public boolean isSub(TreeNode root){
        if(root==null)
            return true;
        boolean b1=isSub(root.left);//左子树是否为同值子树
        boolean b2=isSub(root.right);//右子树是否为同值子树
        //根节点和左右任意一个节点值不同就不是
        if(root.left!=null&&root.left.val!=root.val)
            return false;
        if(root.right!=null&&root.right.val!=root.val)
            return false;
        //如果都满足,加1
        if(b1&&b2)
            sum++;
        return b1&&b2;
    }

}

257. 二叉树的所有路径

给定一个二叉树,返回所有从根节点到叶子节点的路径。

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

示例:

输入:

   1
 /   \
2     3
 \
  5

输出: ["1->2->5", "1->3"]

解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3

解答:

class Solution {

    //保存结果集
    List<String> res=new ArrayList<>();
    
    public List<String> binaryTreePaths(TreeNode root) {
        search(root,new StringBuilder());
        return res;
    }

    //辅助函数,利用StringBuilder拼接
    public void search(TreeNode root,StringBuilder stringBuilder){
        if(root!=null){
            //每次创建一个新的StringBuilder,将上次的值作为拼接初始值
            StringBuilder sb = new StringBuilder(stringBuilder);
            if(root.left==null&&root.right==null) {
                //到达叶子节点,拼接完值就添加到结果集
                sb.append(root.val);
                res.add(sb.toString());
            }else {
                //还没到叶子节点,拼接值之后加一个->
                sb.append(root.val).append("->");
                search(root.left, sb);
                search(root.right, sb);
            }
        }
    }
}

270. 最接近的二叉搜索树值

给定一个不为空的二叉搜索树和一个目标值 target,请在该二叉搜索树中找到最接近目标值 target 的数值。

注意:

  • 给定的目标值 target 是一个浮点数
  • 题目保证在该二叉搜索树中只会存在一个最接近目标值的数

示例:

输入: root = [4,2,5,1,3],目标值 target = 3.714286

    4
   / \
  2   5
 / \
1   3

输出: 4

解答:

class Solution {

    //保存最接近的值
    Integer num=null;

    public int closestValue(TreeNode root, double target) {
        if(root!=null){
            //如果最接近的值不存在或有更接近的值就更新
            if(num==null||Math.abs(root.val-target)<Math.abs(num-target)){
                num=root.val;
            }
            //在左右子树继续寻找
            closestValue(root.left,target);
            closestValue(root.right,target);
        }
        return num;
    }

}

337. 打家劫舍 III

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

示例 1:

输入: [3,2,3,null,3,null,1]

     3
    / \
   2   3
    \   \ 
     3   1

输出: 7 
解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.

解答:

class Solution {

    HashMap<TreeNode,Integer> map=new HashMap<>();

    //计算root节点能偷取到的最大值
    public int rob(TreeNode root) {
        if(root==null)
            return 0;
        //避免重复计算,如果计算过直接返回结果
        if(map.containsKey(root))
            return map.get(root);
        //profit1表示当前节点和四个孙子节点能偷的最大值
        int profit1=root.val;
        if(root.left!=null)
            profit1+=rob(root.left.left)+rob(root.left.right);
        if(root.right!=null)
            profit1+=rob(root.right.left)+rob(root.right.right);
        //不偷当前节点,那么就取两个孩子节点的最大值
        int profit2=rob(root.left)+rob(root.right);
        //比较两种情况的最大值
        int max=Math.max(profit1,profit2);
        //存储结果
        map.put(root,max);
        return max;
    }

}

366. 寻找二叉树的叶子节点

给你一棵二叉树,请按以下要求的顺序收集它的全部节点:

  1. 依次从左到右,每次收集并删除所有的叶子节点
  2. 重复如上过程直到整棵树为空

示例:

输入: [1,2,3,4,5]
  
          1
         / \
        2   3
       / \     
      4   5    

输出: [[4,5,3],[2],[1]]

解答:

class Solution {

    List<List<Integer>> res=new ArrayList<>();//保存结果集
    List<Integer> list=new ArrayList<>();//保存临时结果

    public List<List<Integer>> findLeaves(TreeNode root) {
        if(root==null)
            return res;
        //仍存在叶子节点则递归处理
        while(root.left!=null||root.right!=null){
            help(root,null,list);
            res.add(new ArrayList<>(list));
            list.clear();
        }
        //只剩当前节点
        list.add(root.val);
        res.add(list);
        return res;
    }

    //辅助方法,删除所有叶子节点
    public void help(TreeNode root,TreeNode pre, List<Integer> list){
        if(root!=null){
            //左右节点都为空说明是叶子节点
            if(root.left==null&&root.right==null){
                if(pre!=null){
                    if(pre.left==root)//如果是左叶子则删除
                        pre.left=null;
                    else if(pre.right==root)//如果是右叶子则删除
                        pre.right=null;
                }
                list.add(root.val);
                return;
            }
            //不是叶子节点则递归处理
            help(root.left,root,list);
            help(root.right,root,list);
        }
    }
}

404. 左叶子之和

计算给定二叉树的所有左叶子之和。

示例:

    3
   / \
  9  20
    /  \
   15   7

在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24

解答:

    public int sumOfLeftLeaves(TreeNode root) {
        //空节点值0
        if(root==null)
            return 0;
        int sum=0;
        //如果左节点不为空,左节点的左节点或右节点不为空,递归往左子树查找
        if(root.left!=null&&(root.left.left!=null||root.left.right!=null))
            sum+=sumOfLeftLeaves(root.left);
        //如果右节点不为空,右节点的左节点或右节点不为空,递归往右子树查找
        if(root.right!=null&&(root.right.left!=null||root.right.right!=null))
            sum+=sumOfLeftLeaves(root.right);
        //如果左节点不为空,左节点是叶子节点,就直接相加
        if(root.left!=null&&root.left.left==null&&root.left.right==null)
            sum+=root.left.val;
        return sum;
    }

429. N叉树的层序遍历

给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。

例如,给定一个 3叉树 :

img

返回其层序遍历:

[
     [1],
     [3,2,4],
     [5,6]
]

解答:

    public List<List<Integer>> levelOrder(Node root) {
                List<List<Integer>> result=new ArrayList<>();
        List<Node> trees=new ArrayList<>();
        List<Integer> temp;
        if(root!=null){
            trees.add(root);
            while(!trees.isEmpty()){
                int n=trees.size();
                temp=new ArrayList<>();
                for(int i=0;i<n;i++){
                    Node remove=trees.remove(0);
                    temp.add(remove.val);
                    //和二叉树的层次遍历只有此处不同
                    //遍历孩子节点,不为空就入队
                    for(Node node:remove.children){
                        if(node!=null)
                            trees.add(node);
                    }
                }
                result.add(temp);
            }
        }
        return result;
    }

437. 路径总和 III

给定一个二叉树,它的每个结点都存放着一个整数值。

找出路径和等于给定数值的路径总数。

路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。

示例:

root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8

      10
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1

返回 3。和等于 8 的路径有:

1.  5 -> 3
2.  5 -> 2 -> 1
3.  -3 -> 11

解答:

    public int pathSum(TreeNode root, int sum) {
        if(root==null)
            return 0;
        //结果是当前节点,左节点,右节点分别为根的结果
        return count(root,sum)+pathSum(root.left,sum)+pathSum(root.right,sum);
    }

    public int count(TreeNode root,int sum){
        if(root==null)
            return 0;
        int res=root.val==sum?1:0;
        //在左右子树继续寻找
        return res+count(root.left,sum-root.val)+count(root.right,sum-root.val);
    }

449. 序列化和反序列化二叉搜索树

序列化是将数据结构或对象转换为一系列位的过程,以便它可以存储在文件或内存缓冲区中,或通过网络连接链路传输,以便稍后在同一个或另一个计算机环境中重建。

设计一个算法来序列化和反序列化二叉搜索树。 对序列化/反序列化算法的工作方式没有限制。 您只需确保二叉搜索树可以序列化为字符串,并且可以将该字符串反序列化为最初的二叉搜索树。

编码的字符串应尽可能紧凑。

注意:不要使用类成员/全局/静态变量来存储状态。 你的序列化和反序列化算法应该是无状态的。

解答:

public class Codec {
    
    //通过前序遍历序列化
    public String serialize(TreeNode root) {
        if(root==null)
            return null;
        String str=preorder(root,new StringBuilder());
        return str;
    }

    //前序遍历的字符串
    public String preorder(TreeNode root,StringBuilder sb){
        if(root!=null){
            sb.append(root.val).append(" ");
            preorder(root.left,sb);
            preorder(root.right,sb);
        }
        return sb.toString();
    }
    
    //反序列化
    public TreeNode deserialize(String data) {
        if(data==null)
            return null;
        //双向队列
        LinkedList<Integer> nums = new LinkedList<>();
        //将序列化的数字字符串转化为队列
        for(String s : data.split(" "))
            nums.add(Integer.parseInt(s));
        return helper(Integer.MIN_VALUE, Integer.MAX_VALUE, nums);
    }

    //前序遍历反序列化
    public TreeNode helper(Integer lower, Integer upper, LinkedList<Integer> nums) {
        if (nums.isEmpty()) 
            return null;
        //获取队首节点值
        int val = nums.getFirst();
        //小于最小值或大于最大值返回null
        if (val < lower || val > upper)
             return null;
        //移除队首节点值
        nums.removeFirst();
        TreeNode root = new TreeNode(val);
        //前序遍历,下一个队首节点就是当前节点的左节点
        root.left = helper(lower, val, nums);
        //左子树构成后,下一个队首节点就是当前节点的右节点
        root.right = helper(val, upper, nums);
        return root;
    }

}

450. 删除二叉搜索树中的节点

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

一般来说,删除节点可分为两个步骤:

  1. 首先找到需要删除的节点;
  2. 如果找到了,删除它。

说明: 要求算法时间复杂度为 O(h),h 为树的高度。

示例:

root = [5,3,6,2,4,null,7]
key = 3

    5
   / \
  3   6
 / \   \
2   4   7
给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。
一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。
    5
   / \
  4   6
 /     \
2       7

另一个正确答案是 [5,2,6,null,4,null,7]。
    5
   / \
  2   6
   \   \
    4   7

解答:

    //主要思路是替换值,然后将要删除的节点变为叶子节点直接删除
    public TreeNode deleteNode(TreeNode root, int key) {
        if(root!=null){
            if(key<root.val){//key小于当前节点值,在左子树删除
                root.left=deleteNode(root.left,key);
            }else if(key>root.val){//key大于当前节点值,在右子树删除
                root.right=deleteNode(root.right,key);
            }else{
                if(root.right!=null){//右子树不为空,将节点值替换为右子树最小值,再删除该替换节点
                    root.val=getRightMin(root);
                    root.right=deleteNode(root.right,root.val);
                }else if(root.left!=null){//左子树不为空,将节点值替换为左子树最大值,再删除该替换节点
                    root.val=getLeftMax(root);
                    root.left=deleteNode(root.left,root.val);
                }else{
                    root=null;
                }
            }
        }
        return root;
    }


    //找到右子树的最小节点值
    public int getRightMin(TreeNode root){
        //从右子树开始寻找
        root=root.right;
        //最小值一定在最左节点
        while(root.left!=null)
            root=root.left;
        return root.val;
    }

    //找到左子树的最大节点值
    public int getLeftMax(TreeNode root){
        //从左子树开始寻找
        root=root.left;
        //最大值一定在最右节点
        while(root.right!=null)
            root=root.right;
        return root.val;
    }

501. 二叉搜索树中的众数

给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。

假定 BST 有如下定义:

  • 结点左子树中所含结点的值小于等于当前结点的值
  • 结点右子树中所含结点的值大于等于当前结点的值
  • 左子树和右子树都是二叉搜索树

例如:
给定 BST [1,null,2,2],

   1
    \
     2
    /
   2

返回[2].

提示:如果众数超过1个,不需考虑输出顺序

解答:

class Solution {
    //存放众数
    List<Integer> result=new ArrayList<>();
    //前驱节点值
    int pre;
    //当前节点值计数器
    int count;
    //当前某节点值出现最多的次数
    int max;

    public int[] findMode(TreeNode root) {
        //空节点,不存在众数
        if(root==null)
            return new int[0];
        //初始化
        pre=root.val;
        count=0;
        //辅助方法
        help(root);
        //将结果集中元素输出
        return result.stream().mapToInt(Integer::intValue).toArray();
    }

    //二叉搜索树中序是升序序列,所以按中序遍历
    public void help(TreeNode root){
        if(root==null)
            return;
        //遍历左子树
        help(root.left);
        //处理当前节点
        if(pre==root.val){//当前节点值=前驱节点值,该值计数器+1
            count++;
        }else {//若不等于,更新前驱节点值,计数器初始化1
            pre=root.val;
            count=1;
        }
        if(count==max){//不止一个众数的情况
            result.add(pre);
        }else if(count>max){//当前值出现次数最多,清空值集合并添加
            result.clear();
            result.add(pre);
            max=count;
        }
        //遍历右子树
        help(root.right);
    }
}

508. 出现次数最多的子树元素和

给你一个二叉树的根结点,请你找出出现次数最多的子树元素和。一个结点的「子树元素和」定义为以该结点为根的二叉树上所有结点的元素之和(包括结点本身)。

你需要返回出现次数最多的子树元素和。如果有多个元素出现的次数相同,返回所有出现次数最多的子树元素和(不限顺序)。

示例 1:
输入:

  5
 /  \
2   -3

返回 [2, -3, 4],所有的值均只出现一次,以任意顺序返回所有值。

解答:

class Solution {

    List<Integer> list=new ArrayList<>();
    HashMap<Integer,Integer> map=new HashMap<>();//保存子树和与次数的对应关系
    int max=0;//保存最大次数

    public int[] findFrequentTreeSum(TreeNode root) {
        help(root);
        //遍历次数,如果次数等于最大次数就存入list
        Set<Integer> keys = map.keySet();
        for(int num:keys){
            if(map.get(num)==max)
                list.add(num);
        }
        //list转为int[]
        int[] res=new int[list.size()];
        for(int i=0;i<res.length;i++){
            res[i]=list.get(i);
        }
        return res;
    }

    public int help(TreeNode root){
        if(root==null)
            return 0;
        //当前子树和等于自己的值加上左右子树和
        int val=root.val+help(root.left)+help(root.right);
        //将子树和以及对应出现次数存入map
        int time=map.getOrDefault(val,0)+1;
        map.put(val,time);
        //更新出现最多的次数
        if(time>max)
            max=time;
        return val;
    }

}

513. 找树左下角的值

给定一个二叉树,在树的最后一行找到最左边的值。

示例 1:

输入:

    2
   / \
  1   3

输出:
1

解答:

class Solution {

    int max=-1;//保存深度
    int val=0;//保存最后一层最左节点值

    public int findBottomLeftValue(TreeNode root) {
        help(root,-1);
        return val;
    }

    public void help(TreeNode root,int depth){
        if(root!=null){
            depth=depth+1;
            //第一次大于最大深度的就是最左节点
            if(depth>max){
                max=depth;
                val=root.val;
            }
            help(root.left,depth);
            help(root.right,depth);
        }
    }
}

515. 在每个树行中找最大值

您需要在二叉树的每一行中找到最大的值。

示例:

输入: 

          1
         / \
        3   2
       / \   \  
      5   3   9 

输出: [1, 3, 9]

解答:

class Solution {

    int max=-1;//保存最大深度
    //key是深度,value是该深度的最大值
    HashMap<Integer,Integer> map=new HashMap<>();
    
    public List<Integer> largestValues(TreeNode root) {
        List<Integer> list=new ArrayList<>();
        help(root,-1);
        for(int i=0;i<=max;i++){
            list.add(map.get(i));
        }
        return list;
    }

    public void help(TreeNode root,int depth){
        if(root!=null){
            depth=depth+1;
            //更新最大深度
            if(depth>max){
                max=depth;
            }
            //当前深度还没有值或比当前值大
            if(!map.containsKey(depth)||root.val>map.get(depth))
                map.put(depth,root.val);
            help(root.left,depth);
            help(root.right,depth);
        }
    }
}

530. 二叉搜索树的最小绝对差

给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值。

示例:

输入:

   1
    \
     3
    /
   2

输出:
1

解释:
最小绝对差为 1,其中 2 和 1 的差的绝对值为 1(或者 2 和 3)。

解答:

class Solution {

    //保存最小值
    int min=Integer.MAX_VALUE;
    //保存前驱节点值
    int pre=0;

    //绝对值最小,肯定是相邻数之间产生,用中序遍历辅助
    public int getMinimumDifference(TreeNode root) {
        pre=root.val;
        inorder(root);
        return min;
    }

    //中序遍历,更新差值
    public void inorder(TreeNode root){
        if(root==null)
            return;
        inorder(root.left);
        if(root.val!=pre){
            int temp=Math.abs(root.val-pre);
            if(temp<min)
                min=temp;
            pre=root.val;
        }
        inorder(root.right);
    }
}

538. 把二叉搜索树转换为累加树

给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。

例如:

输入: 原始二叉搜索树:
              5
            /   \
           2     13

输出: 转换为累加树:
             18
            /   \
          20     13

解答:

class Solution {

    //保存当前总和
    int sum=0;

    //从最右节点开始累加,采用逆中序遍历
    public TreeNode convertBST(TreeNode root) {
        if(root!=null){
            convertBST(root.right);
            //累加
            sum+=root.val;
            //更新当前节点
            root.val=sum;
            convertBST(root.left);
        }
        return root;
    }
    
}

543. 二叉树的直径

给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。

示例 :
给定二叉树

          1
         / \
        2   3
       / \     
      4   5    

返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。

**注意:**两结点之间的路径长度是以它们之间边的数目表示。

解答:

class Solution {

    //保存最长路径
    int max=0;

    public int diameterOfBinaryTree(TreeNode root) {
        if(root==null)
            return 0;
        maxDepth(root);
        return max;
    }

    //相当于求最大深度时多了一行更新左右深度和的最大值更新操作
    public int maxDepth(TreeNode root) {
        if(root==null)
            return 0;
        int hL=maxDepth(root.left);
        int hR=maxDepth(root.right);
        //更新直径最大值
        max=Math.max(max,hL+hR);
        return Math.max(hL,hR)+1;
    }

}

559. N叉树的最大深度

给定一个 N 叉树,找到其最大深度。

最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。

例如,给定一个 3叉树 :

img

我们应返回其最大深度,3。

说明:

  1. 树的深度不会超过 1000
  2. 树的节点总不会超过 5000

解答:

    public int maxDepth(Node root) {
        if(root==null)
            return 0;
        //保存子树节点数最大值
        int depth=0;
        //在子树中寻找节点数的最大值,其实和二叉树最大高度一样,只是换了一个形式,使用for循环
        for(Node node:root.children){
            depth=Math.max(depth,maxDepth(node));
        }
        //返回子树最大值加自身节点数1
        return depth+1;
    }

563. 二叉树的坡度

给定一个二叉树,计算整个树的坡度。

一个树的节点的坡度定义即为,该节点左子树的结点之和和右子树结点之和的差的绝对值。空结点的的坡度是0。

整个树的坡度就是其所有节点的坡度之和。

示例:

输入: 
         1
       /   \
      2     3
输出: 1
解释: 
结点的坡度 2 : 0
结点的坡度 3 : 0
结点的坡度 1 : |2-3| = 1
树的坡度 : 0 + 0 + 1 = 1

解答:

class Solution {
    
    //坡度和
    int p=0;

    public int findTilt(TreeNode root) {
        if(root==null)
            return 0;
        postorder(root);
        return p;
    }

    //后序遍历计算某个节点包括自身的节点和,顺便计算该节点的坡度值,累加到结果中
    public int postorder(TreeNode root){
        if(root==null)
            return 0;
        //左子树的节点和
        int sumL=postorder(root.left);
        //右子树的节点和
        int sumR=postorder(root.right);
        //累加当前节点坡度
        p+=Math.abs(sumL-sumR);
        //返回当前节点的节点和
        return sumL+sumR+root.val;
    }
}

572. 另一个树的子树

给定两个非空二叉树 st,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。

示例 1:
给定的树 s:

     3
    / \
   4   5
  / \
 1   2

给定的树 t:

   4 
  / \
 1   2

返回 true,因为 t 与 s 的一个子树拥有相同的结构和节点值。

示例 2:
给定的树 s:

     3
    / \
   4   5
  / \
 1   2
    /
   0

给定的树 t:

   4
  / \
 1   2

返回 false

解答:

    public boolean isSubtree(TreeNode s, TreeNode t) {
        if(s==null)
            return false;
        //以当前节点为根,或者在左右子树中继续寻找
        return isSame(s,t)||isSubtree(s.left,t)||isSubtree(s.right,t);
    }

    //判断两个分别以s和t作为根节点的树是否相同
    public boolean isSame(TreeNode s,TreeNode t){
        //都为空为true
        if(s==null&&t==null)
            return true;
        //其中一个为空另一个不为空为false
        if((s!=null&&t==null)||(s==null&&t!=null))
            return false;
        //根节点值不同为false
        if(s.val!=t.val)
            return false;
        //比较对应的左子树和右子树
        return isSame(s.left,t.left)&&isSame(s.right,t.right);
    }

589. N叉树的前序遍历

给定一个 N 叉树,返回其节点值的前序遍历

例如,给定一个 3叉树 :

img

返回其前序遍历: [1,3,5,6,2,4]

说明: 递归法很简单,你可以使用迭代法完成此题吗?

递归解答:

class Solution {

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

    public List<Integer> preorder(Node root) {
        if(root!=null){
            list.add(root.val);
            for(Node node:root.children){
                preorder(node);
            }
        }
        return list;
    }
}

迭代解答:

class Solution {

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

    public List<Integer> preorder(Node root) {
        Stack<Node> stack=new Stack<>();
        if(root!=null)
            stack.push(root);
        while (!stack.isEmpty()){
            //出栈一个节点
            Node pop = stack.pop();
            //添加当前节点值到结果集
            list.add(pop.val);
            //将子节点逆序入栈
            Collections.reverse(pop.children);
            for(Node node:pop.children){
                stack.push(node);
            }
        }
        return list;
    }
}

590. N叉树的后序遍历

难度简单63

给定一个 N 叉树,返回其节点值的后序遍历

例如,给定一个 3叉树 :

img

返回其后序遍历: [5,6,3,2,4,1].

说明: 递归法很简单,你可以使用迭代法完成此题吗?

递归解答:

class Solution {

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

    public List<Integer> postorder(Node root) {
        if(root!=null){           
            for(Node node:root.children){
                postorder(node);
            }
            list.add(root.val);
        }
        return list;
    }
}

迭代解答:

class Solution {

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

    public List<Integer> postorder(Node root) {
        Stack<Node> stack=new Stack<>();
        if(root!=null)
            stack.push(root);
        while (!stack.isEmpty()){
            //出栈一个节点
            Node pop = stack.pop();
            //添加当前节点值到结果集
            list.add(pop.val);
            //将子节点顺序入栈
            for(Node node:pop.children){
                stack.push(node);
            }
        }
        //将结果逆序即为后序遍历结果
        Collections.reverse(list);
        return list;
    }
}

606. 根据二叉树创建字符串

你需要采用前序遍历的方式,将一个二叉树转换成一个由括号和整数组成的字符串。

空节点则用一对空括号 “()” 表示。而且你需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。

示例 1:

输入: 二叉树: [1,2,3,4]
       1
     /   \
    2     3
   /    
  4     

输出: "1(2(4))(3)"

解释: 原本将是“1(2(4)())(3())”,
在你省略所有不必要的空括号对之后,
它将是“1(2(4))(3)”。

解答:

	public String tree2str(TreeNode t) {
        if(t==null)
            return "";
        StringBuilder sb=new StringBuilder();
        sb.append(t.val);
        //左右子树任意一个不为空就要添加左子树
        if(t.left!=null||t.right!=null)
            sb.append("(").append(tree2str(t.left)).append(")");
        //右子树空可以省略
        if(t.right!=null)
            sb.append("(").append(tree2str(t.right)).append(")");
        return sb.toString();
    }

617. 合并二叉树

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。

你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。

示例 1:

输入: 
	Tree 1                     Tree 2                  
          1                         2                             
         / \                       / \                            
        3   2                     1   3                        
       /                           \   \                      
      5                             4   7                  
输出: 
合并后的树:
	     3
	    / \
	   4   5
	  / \   \ 
	 5   4   7

注意: 合并必须从两个树的根节点开始。

解答:

    public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
        //t1是空将t2作为新节点
        if(t1==null)
            return t2;
        //t1、t2都不为空,将t2的节点值加到t1上,然后将合并的左子树作为t1的左节点,合并的右子树作为t1的右节点
        if(t2!=null){
            t1.val+=t2.val;
            t1.left=mergeTrees(t1.left,t2.left);
            t1.right=mergeTrees(t1.right,t2.right);
        }
        return t1;
    }

623. 在二叉树中增加一行

给定一个二叉树,根节点为第1层,深度为 1。在其第 d 层追加一行值为 v 的节点。

添加规则:给定一个深度值 d (正整数),针对深度为 d-1 层的每一非空节点 N,为 N 创建两个值为 v 的左子树和右子树。

N 原先的左子树,连接为新节点 v 的左子树;将 N 原先的右子树,连接为新节点 v 的右子树。

如果 d 的值为 1,深度 d - 1 不存在,则创建一个新的根节点 v,原先的整棵树将作为 v 的左子树。

示例 1:

输入: 
二叉树如下所示:
       4
     /   \
    2     6
   / \   / 
  3   1 5   

v = 1

d = 2

输出: 
       4
      / \
     1   1
    /     \
   2       6
  / \     / 
 3   1   5   

解答:

    public TreeNode addOneRow(TreeNode root, int v, int d) {
        //d为1的特殊情况,创建根节点,直接将原先的树作为左子树
        if(d==1){
            TreeNode newRoot=new TreeNode(v);
            newRoot.left=root;
            return newRoot;
        }
        add(root,v,1,d);
        return root;
    }

    //当depth=d-1时添加树
    public void add(TreeNode root,int v,int depth,int d){
        //当前节点为空不用再继续找了
        if(root==null)
            return;
        //达到目标深度
        if(depth==d-1){
            TreeNode v1=new TreeNode(v);
            v1.left=root.left;
            root.left=v1;
            TreeNode v2=new TreeNode(v);
            v2.right=root.right;
            root.right=v2;
        }else{//继续找
            add(root.left,v,depth+1,d);
            add(root.right,v,depth+1,d);
        }
    }

637. 二叉树的层平均值

给定一个非空二叉树, 返回一个由每层节点平均值组成的数组.

示例 1:

输入:
    3
   / \
  9  20
    /  \
   15   7
输出: [3, 14.5, 11]
解释:
第0层的平均值是 3,  第1层是 14.5, 第2层是 11. 因此返回 [3, 14.5, 11].

解答:

    public List<Double> averageOfLevels(TreeNode root) {
        //结果集
        List<Double> result=new ArrayList<>();
        //节点队列
        List<TreeNode> list=new ArrayList<>();
        //头结点入队
        list.add(root);
        //保存每一层的节点和
        double sum=0;
        while(!list.isEmpty()){
            sum=0;//初始化和
            //每一层的节点数就是当前队列元素数
            int n=list.size();
            for(int i=0;i<n;i++){
                TreeNode remove=list.remove(0);
                sum+=remove.val;//累加该层节点值
                //如果有左右节点要入队
                if(remove.left!=null)
                    list.add(remove.left);
                if(remove.right!=null)
                    list.add(remove.right);
            }
            //该层平均值
            sum=sum/n;
            result.add(sum);
        }
        return result;
    }

652. 寻找重复的子树

给定一棵二叉树,返回所有重复的子树。对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可。

两棵树重复是指它们具有相同的结构以及相同的结点值。

示例 1:

        1
       / \
      2   3
     /   / \
    4   2   4
       /
      4

下面是两个重复的子树:

      2
     /
    4

    4

因此,你需要以列表的形式返回上述重复子树的根结点。

解答:

class Solution {

    //全局变量用于提供唯一id
    int n=1;
    //保存内容和对应序号id的关系,内容相同id相同
    HashMap<String,Integer> map1=new HashMap<>();
    //保存唯一序号id和出现次数的关系,key是id,value是次数
    HashMap<Integer,Integer> map2=new HashMap<>();
    //结果集
    List<TreeNode> list=new ArrayList<>();

    public List<TreeNode> findDuplicateSubtrees(TreeNode root) {
        if(root!=null)
        getID(root);
        return list;
    }

    public int getID(TreeNode root){
        if(root==null)
            return 0;
        //当前节点信息(转为字符串)
        String unique=""+root.val+getID(root.left)+getID(root.right);
        //计算唯一id
        int id=map1.computeIfAbsent(unique,u->n++);
        //获取出现次数
        int time=map2.getOrDefault(id,0)+1;
        map2.put(id,time);
        //只有第二次出现时添加,避免重复
        if(time==2)
            list.add(root);
        return id;
    }
}

653. 两数之和 IV - 输入 BST

给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。

案例 1:

输入: 
    5
   / \
  3   6
 / \   \
2   4   7

Target = 9

输出: True

解答:

class Solution {
    
    //保存节点值
    HashSet<Integer> set=new HashSet<>();
    
    public boolean findTarget(TreeNode root, int k) {
        if(root!=null){
            //如果集合存在一个加上当前节点值和为k的值,就说明存在
            if(set.contains(k-root.val))
                return true;
            //如果不存在,添加当前值,在左右子树寻找
            set.add(root.val);
            return findTarget(root.left, k)||findTarget(root.right, k);
        }
        return false;
    }

}

654. 最大二叉树

给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下:

  1. 二叉树的根是数组中的最大元素。
  2. 左子树是通过数组中最大值左边部分构造出的最大二叉树。
  3. 右子树是通过数组中最大值右边部分构造出的最大二叉树。

通过给定的数组构建最大二叉树,并且输出这个树的根节点。

示例 :

输入:[3,2,1,6,0,5]
输出:返回下面这棵树的根节点:

      6
    /   \
   3     5
    \    / 
     2  0   
       \
        1

解答:

    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return buildTree(nums,0,nums.length-1);
    }

    public TreeNode buildTree(int[] nums,int start,int end){        
        if(start>end)//开始大于结尾说明空树
            return null;        
        else if(start==end)//相同的话直接创建节点返回
            return new TreeNode(nums[start]);
        else{           
            int index=getMaxIndex(nums,start,end);//计算当前最大值下标           
            TreeNode root=new TreeNode(nums[index]);//创建该节点           
            root.left=buildTree(nums,start,index-1);//下标以左创建左子树
            root.right=buildTree(nums,index+1,end);//下标以右创建右子树
            return root;
        }
    }


    //计算nums数组从start到end范围内的最大值的索引
    public int getMaxIndex(int[] nums,int start,int end){
        int index=start;
        int max=nums[start];
        for(int i=start+1;i<=end;i++){
            if(nums[i]>max){
                max=nums[i];
                index=i;
            }
        }
        return index;
    }

662. 二叉树最大宽度

给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与**满二叉树(full binary tree)**结构相同,但一些节点为空。

每一层的宽度被定义为两个端点(该层最左和最右的非空节点,两端点间的null节点也计入长度)之间的长度。

示例 1:

输入: 

           1
         /   \
        3     2
       / \     \  
      5   3     9 

输出: 4
解释: 最大值出现在树的第 3 层,宽度为 4 (5,3,null,9)。

解答:

class Solution {

    //key是深度,value是该深度第一个出现的节点位置即最左节点
    HashMap<Integer,Integer> map=new HashMap<>();
    //当前最大宽度
    int max=0;

    public int widthOfBinaryTree(TreeNode root) {
        help(root,0,0);
        return max;
    }

    //前序遍历
    public void help(TreeNode root,int depth,int pos){
        if(root!=null){
            depth=depth+1;//当前深度
            //如果当前深度还没有存入map,说明找到了当前深度最左节点
            if(!map.containsKey(depth))
                map.put(depth,pos);
            int len=pos-map.get(depth)+1;
            if(len>max)
                max=len;
            help(root.left,depth,pos*2);
            help(root.right,depth,pos*2+1);
        }
    }
}

669. 修剪二叉搜索树

给定一个二叉搜索树,同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。

示例 1:

输入: 
    1
   / \
  0   2

  L = 1
  R = 2

输出: 
    1
      \
       2

解答:

    public TreeNode trimBST(TreeNode root, int L, int R) {
        if(root!=null){
            if(root.val==L) //当前节点=左临界值,将左子树剪掉
                root.left=null;
            else if(root.val==R)//当前节点=右临界值,将右子树剪掉
                root.right=null;
            else if(root.val<L)//当前节点<左临界值,将右子树作为新的左节点
                return trimBST(root.right,L,R);
            else if(root.val>R)//当前节点>右临界值,将左子树作为新的右节点
                return trimBST(root.left,L,R);
            if(root.left!=null)//左子树不为空,修剪
                root.left=trimBST(root.left,L,R);
            if(root.right!=null)//右子树不为空,修剪
                root.right=trimBST(root.right,L,R);
        }
        return root;
    }

671. 二叉树中第二小的节点

给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 20。如果一个节点有两个子节点的话,那么这个节点的值不大于它的子节点的值。

给出这样的一个二叉树,你需要输出所有节点中的**第二小的值。**如果第二小的值不存在的话,输出 -1

示例 1:

输入: 
    2
   / \
  2   5
     / \
    5   7

输出: 5
说明: 最小的值是 2 ,第二小的值是 5 。

解答:

    public int findSecondMinimumValue(TreeNode root) {
        //节点空,或者左右节点都为空,返回-1
        if(root==null||(root.left==null&&root.right==null))
            return -1;
        //计算左节点的值,如果等于根节点就递归在左子树计算,右节点同理
        int left=root.left.val;
        if(left==root.val)
            left=findSecondMinimumValue(root.left);
        int right=root.right.val;
        if(right==root.val)
            right=findSecondMinimumValue(root.right);
        //左右节点值都有效,取较小的
        if(left!=-1&&right!=-1)
            return Math.min(left,right);
        //左边有效
        if(left!=-1)
            return left;
        //右边有效
        return right;
    }

687. 最长同值路径

给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。

注意:两个节点之间的路径长度由它们之间的边数表示。

示例 1:

输入:

              5
             / \
            4   5
           / \   \
          1   1   5

输出:

2

解答:

class Solution {
    int max=0;//保存最大结果

    public int longestUnivaluePath(TreeNode root) {
        if(root==null)
            return 0;
        longPath(root);
        return max;    
    }

    //以当前节点值为相同值,求左右子树中相同值较多的节点数
    public int longPath(TreeNode root){
        if(root==null)
            return 0;
        //求左右子树中相同节点数
        int left=longPath(root.left);
        int right=longPath(root.right);
        int pathL=0;
        int pathR=0;
        //如果左节点值和当前值相同,左路径就是左节点的路径长+1
        if(root.left!=null&&root.val==root.left.val)
            pathL=left+1;
        //如果右节点值和当前值相同,右路径就是右节点的路径长+1
        if(root.right!=null&&root.val==root.right.val)
            pathR=right+1;
        //经过当前节点的最大路径长,即当前最大路径长度和当前节点左右路径长度之和的较大值
        max=Math.max(max,pathL+pathR);
        //不经过当前节点,返回左右节点中相同节点较多的那个
        return Math.max(pathL,pathR);
    }
}

700. 二叉搜索树中的搜索

给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。

例如,

给定二叉搜索树:

        4
       / \
      2   7
     / \
    1   3

和值: 2

你应该返回如下子树:

      2     
     / \   
    1   3

在上述示例中,如果要找的值是 5,但因为没有节点值为 5,我们应该返回 NULL

解答:

    public TreeNode searchBST(TreeNode root, int val) {
        if(root!=null){
            //找到直接返回
            if(root.val==val)
                return root;
            //在左子树找到就返回,否则返回右子树的结果
            TreeNode res= searchBST(root.left,val);
            if(res!=null)
                return res;
            return searchBST(root.right,val);
        }
        return root;
    }

701. 二叉搜索树中的插入操作

给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 保证原始二叉搜索树中不存在新值。

注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回任意有效的结果。

解答:

    public TreeNode insertIntoBST(TreeNode root, int val) {
        if(root!=null){
            if(val<root.val){
                if(root.left==null)
                    root.left=new TreeNode(val);
                else
                    insertIntoBST(root.left,val);
            }else{
                if(root.right==null)
                    root.right=new TreeNode(val);
                else
                    insertIntoBST(root.right,val);
            }
        }
        return root;
    }

783. 二叉搜索树节点最小距离

给定一个二叉搜索树的根节点 root,返回树中任意两节点的差的最小值。

和530题一样。


814. 二叉树剪枝

给定二叉树根结点 root ,此外树的每个结点的值要么是 0,要么是 1。

返回移除了所有不包含 1 的子树的原二叉树。

( 节点 X 的子树为 X 本身,以及所有 X 的后代。)

示例1:
输入: [1,null,0,0,1]
输出: [1,null,0,null,1]
 
解释: 
只有红色节点满足条件“所有不包含 1 的子树”。
右图为返回的答案。

解答:

    public TreeNode pruneTree(TreeNode root) {
        if(root!=null){
            if(root.val==0&&root.left==null&&root.right==null)
                return null;
            //左节点满足条件就将其移除
            TreeNode removeL=pruneTree(root.left);
            if(removeL==null)
                root.left=null;
            //右节点满足条件就将其移除
            TreeNode removeR=pruneTree(root.right);
            if(removeR==null)
                root.right=null;
            //左右节点都满足条件且该节点为0才满足
            if(root.val==0&&removeL==null&&removeR==null){
                return null;
            }
        }
        return root;
    }

872. 叶子相似的树

请考虑一颗二叉树上所有的叶子,这些叶子的值按从左到右的顺序排列形成一个 叶值序列

img

举个例子,如上图所示,给定一颗叶值序列为 (6, 7, 4, 9, 8) 的树。

如果有两颗二叉树的叶值序列是相同,那么我们就认为它们是 叶相似 的。

如果给定的两个头结点分别为 root1root2 的树是叶相似的,则返回 true;否则返回 false

解答:

class Solution {
    //保存root1的叶子
    List<Integer> res1 = new ArrayList<>();
    //保存root2的叶子
    List<Integer> res2 = new ArrayList<>();

    public boolean leafSimilar(TreeNode root1, TreeNode root2) {
        postOrder(root1,res1);
        postOrder(root2,res2);
        //两个叶子集合长度不等一定不等
        if(res1.size()!=res2.size())
            return false;
        //按顺序比较元素
        for (int i=0;i<res1.size();i++){
            if(!res1.get(i).equals(res2.get(i)))
                return false;
        }
        return true;
    }

    //后序遍历
    public void postOrder(TreeNode root,List<Integer> list){
        if(root!=null){
            postOrder(root.left,list);
            postOrder(root.right,list);
            //是叶子节点就添加值到集合
            if(root.left==null&&root.right==null)
                list.add(root.val);
        }
    }

}

894. 所有可能的满二叉树

满二叉树是一类二叉树,其中每个结点恰好有 0 或 2 个子结点。

返回包含 N 个结点的所有可能满二叉树的列表。 答案的每个元素都是一个可能树的根结点。

答案中每个树的每个结点必须node.val=0

你可以按任何顺序返回树的最终列表。

示例:

输入:7
输出:[[0,0,0,null,null,0,0,null,null,0,0],[0,0,0,null,null,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,null,null,null,null,0,0],[0,0,0,0,0,null,null,0,0]]
解释:

解答:

class Solution {

    public List<TreeNode> allPossibleFBT(int n) {
        if(n==0)
            return new ArrayList<TreeNode>();
        return createTree(n);
    }

    //跟95题类似
    public List<TreeNode> createTree(int n){
        //保存结果集
        List<TreeNode> result=new ArrayList<>();
        if(n==1){
            result.add(new TreeNode(0));
            return result;
        }
        //用n个节点构造满二叉树,除去根节点还有n-1个可用
        //左边1个,右边n-2个、左边3个,右边n-4个、...左边n-2个,右边1个
        for(int i=1;i<n-1;i+=2){
            //左边节点构造的左子树           
            List<TreeNode> listL=createTree(i);
            //右边节点构造的右子树
            List<TreeNode> listR=createTree(n-1-i);
            //左右子树分别取出一个全组和
            for(TreeNode nodeL:listL){
                for(TreeNode nodeR:listR){
                    //节点全部为0
                    TreeNode root=new TreeNode(0);
                    root.left=nodeL;
                    root.right=nodeR;
                    result.add(root);
                }
            }
        }
        return result;
    }

}

897. 递增顺序查找树

给你一个树,请你 按中序遍历 重新排列树,使树中最左边的结点现在是树的根,并且每个结点没有左子结点,只有一个右子结点。

示例 :

输入:[5,3,6,2,4,null,8,1,null,null,null,7,9]

       5
      / \
    3    6
   / \    \
  2   4    8
 /        / \ 
1        7   9

输出:[1,null,2,null,3,null,4,null,5,null,6,null,7,null,8,null,9]

 1
  \
   2
    \
     3
      \
       4
        \
         5
          \
           6
            \
             7
              \
               8
                \
                 9  

解答:

    //根节点的前一个结点
    TreeNode pre=new TreeNode(-1);
    //因为pre会移动,用cur保存根节点的前一个结点
    TreeNode cur=pre;

    //中序遍历
    public TreeNode increasingBST(TreeNode root) {
        if(root!=null){
            increasingBST(root.left);
            //pre的右节点值是当前结点的值
            pre.right=new TreeNode(root.val);
            //pre移动到自己的右节点形成链
            pre=pre.right;
            increasingBST(root.right);
            //返回初始结点的下一个即根节点
            return cur.right;
        }
        return root;
    }

938. 二叉搜索树的范围和

给定二叉搜索树的根结点 root,返回 LR(含)之间的所有结点的值的和。

二叉搜索树保证具有唯一的值。

示例 1:

输入:root = [10,5,15,3,7,null,18], L = 7, R = 15
输出:32

解答:

class Solution {

    //保存结果值
    int sum=0;

    //二叉树的中序遍历是递增序列,所以使用中序序列遍历
    public int rangeSumBST(TreeNode root, int L, int R) {
        if(root!=null){
            //如果小于L,往左寻找没有意义
            if(root.val>L)
                rangeSumBST(root.left,L,R);
            if(root.val>=L&&root.val<=R)
                sum+=root.val;
            //如果大于R,往右寻找没有意义
            if(root.val<R)
                rangeSumBST(root.right,L,R);
        }
        return sum;
    }
    
}

965. 单值二叉树

如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。

只有给定的树是单值二叉树时,才返回 true;否则返回 false

示例 1:

img
输入:[1,1,1,1,1,null,1]
输出:true

解答:

class Solution {

    //保存单值
    private int unique=0;

    public boolean isUnivalTree(TreeNode root) {
        if(root==null)
            return true;
        unique=root.val;
        return isSame(root);
    }

    //当前节点和左右节点值是否一致
    public boolean isSame(TreeNode root){
        if(root==null)
            return true;
        if(root.val!=unique)
            return false;
        return isSame(root.left)&&isSame(root.right);
    }
}

993. 二叉树的堂兄弟节点

在二叉树中,根节点位于深度 0 处,每个深度为 k 的节点的子节点位于深度 k+1 处。如果二叉树的两个节点深度相同,但父节点不同,则它们是一对堂兄弟节点。我们给出了具有唯一值的二叉树的根节点 root,以及树中两个不同节点的值 xy。只有与值 xy 对应的节点是堂兄弟节点时,才返回 true。否则,返回 false

示例 1:
img

输入:root = [1,2,3,4], x = 4, y = 3
输出:false

解答:

class Solution {

    int dep=0;

    public boolean isCousins(TreeNode root, int x, int y) {
        //第1个节点的深度值
        depth(root,x,0);
        int dx=dep;
        //第2个节点的深度值
        depth(root,y,0);
        int dy=dep;
        //深度值不等,返回false
        if(dx!=dy)
            return false;
        //深度值相同,如果父节点不同就返回true,相同返回false
        return isSameFather(root,x,y);
    }

    //计算节点的深度
    public void depth(TreeNode root,int val,int depth){
        if(root!=null){
            if(root.val==val)
                dep=depth;
            else{
                depth(root.left,val,depth+1);
                depth(root.right,val,depth+1);
            }
        }
    }

    //判断两个节点的父节点是否相同
    public boolean isSameFather(TreeNode root,int x,int y){
        if(root!=null){
            //x和y分别是左-右节点,返回false
            if(root.left!=null&&root.left.val==x&&root.right!=null&&root.right.val==y)
                return false;
            //x和y分别是右-左节点,返回false
            if(root.left!=null&&root.left.val==y&&root.right!=null&&root.right.val==x)
                return false;
            //判断左右子树
            return isSameFather(root.left,x,y)&&isSameFather(root.right,x,y);
        }
        return true;
    }

}

1008. 先序遍历构造二叉树

返回与给定先序遍历 preorder 相匹配的二叉搜索树(binary search tree)的根结点。

(回想一下,二叉搜索树是二叉树的一种,其每个节点都满足以下规则,对于 node.left 的任何后代,值总 < node.val,而 node.right 的任何后代,值总 > node.val。此外,先序遍历首先显示节点的值,然后遍历 node.left,接着遍历 node.right。)

示例:

输入:[8,5,1,7,10,12]
输出:[8,5,10,1,7,null,12]

解答:

class Solution {

    //全局变量,标识当前遍历的节点索引
    int index=0;

    public TreeNode bstFromPreorder(int[] preorder) {
        return help(preorder,Integer.MIN_VALUE,Integer.MAX_VALUE);
    }

    public TreeNode help(int[] preorder,int min,int max){
        if(index==preorder.length)
            return null;
        //获取当前节点值
        int val=preorder[index];
        //当前节点值不在范围内
        if(val<min||val>max)
            return null;
        TreeNode root=new TreeNode(val);
        index++;//使用了一个节点,继续下一个
        //左节点的值肯定小于val,更新max
        root.left=help(preorder,min,val);
        //右节点的值肯定大于val,更新min
        root.right=help(preorder,val,max);
        return root;
    }
}

1022. 从根到叶的二进制数之和

给出一棵二叉树,其上每个结点的值都是 01 。每一条从根到叶的路径都代表一个从最高有效位开始的二进制数。例如,如果路径为 0 -> 1 -> 1 -> 0 -> 1,那么它表示二进制数 01101,也就是 13

对树上的每一片叶子,我们都要找出从根到该叶子的路径所表示的数字。

10^9 + 7,返回这些数字之和。

示例:

img
输入:[1,0,1,0,1,0,1]
输出:22
解释:(100) + (101) + (110) + (111) = 4 + 5 + 6 + 7 = 22

解答:

class Solution {
    
    public int sumRootToLeaf(TreeNode root) {
        return add(root,0);
    }

    public int add(TreeNode root,int num){
        if(root!=null){
            //左移一位加上当前值
            num=(num<<1)+root.val;
            //返回累加到根节点的值
            if(root.left==null&&root.right==null)
                return num;
            //返回左右节点值的和
            return add(root.left,num)+add(root.right,num);
        }
        return 0;
    }
}

1104. 二叉树寻路

在一棵无限的二叉树上,每个节点都有两个子节点,树中的节点 逐行 依次按 “之” 字形进行标记。

如下图所示,在奇数行(即,第一行、第三行、第五行……)中,按从左到右的顺序进行标记;

而偶数行(即,第二行、第四行、第六行……)中,按从右到左的顺序进行标记。

img

给你树上某一个节点的标号 label,请你返回从根节点到该标号为 label 节点的路径,该路径是由途经的节点标号所组成的。

示例 1:

输入:label = 14
输出:[1,3,4,14]

解答:

    public List<Integer> pathInZigZagTree(int label) {
        LinkedList<Integer> list=new LinkedList<>();
        while(label!=0){
            list.addFirst(label);
            label=label/2;
        }
        if(list.size()%2==0){
            for(int i=0;i<list.size()-1;i+=2){
                //该层起始位置
                int start = (int) Math.pow(2, i);
                //该层偏移位置
                int move=(int)Math.pow(2,i+1)-list.get(i)-1;
                //正确的值
                list.set(i,start+move);
            }
        }else{
            for(int i=1;i<list.size()-1;i+=2){
                //该层起始位置
                int start = (int) Math.pow(2, i);
                //该层偏移位置
                int move=(int)Math.pow(2,i+1)-list.get(i)-1;
                //正确的值
                list.set(i,start+move);
            }
        }
        return list;
    }

1261. 在受污染的二叉树中查找元素

给出一个满足下述规则的二叉树:

  1. root.val == 0
  2. 如果 treeNode.val == xtreeNode.left != null,那么 treeNode.left.val == 2 * x + 1
  3. 如果 treeNode.val == xtreeNode.right != null,那么 treeNode.right.val == 2 * x + 2

现在这个二叉树受到「污染」,所有的 treeNode.val 都变成了 -1

请你先还原二叉树,然后实现 FindElements 类:

  • FindElements(TreeNode* root) 用受污染的二叉树初始化对象,你需要先把它还原。
  • bool find(int target) 判断目标值 target 是否存在于还原后的二叉树中并返回结果。

示例 1:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fKiPB5eR-1588937561406)(https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2019/11/16/untitled-diagram-4-1.jpg)]

输入:
["FindElements","find","find"]
[[[-1,null,-1]],[1],[2]]
输出:
[null,false,true]
解释:
FindElements findElements = new FindElements([-1,null,-1]); 
findElements.find(1); // return False 
findElements.find(2); // return True 

解答:

class FindElements {

    HashSet<Integer> set=new HashSet<>();

    public FindElements(TreeNode root) {
        recover(root,0);
    }
    
    public boolean find(int target) {
        return set.contains(target);
    }

    public void recover(TreeNode root,int val){
        if(root!=null){
            root.val=val;
            set.add(val);//将正确的值存储在set集合
            recover(root.left,2*val+1);
            recover(root.right,2*val+2);
        }
    }
}

1302. 层数最深叶子节点的和

给你一棵二叉树,请你返回层数最深的叶子节点的和。

示例:

img

输入:root = [1,2,3,4,5,null,6,7,null,null,null,null,8]
输出:15

解答:

class Solution {

    int max=-1;//保存深度
    int sum=0;//保存最后一层的节点和

    public int deepestLeavesSum(TreeNode root) {
        help(root,0);
        return sum;
    }

    public void help(TreeNode root,int depth){
        if(root!=null){
            depth=depth+1;
            if(depth>max){
                max=depth;
                sum=root.val;
            }else if(depth==max){
                sum+=root.val;
            }
            help(root.left,depth);
            help(root.right,depth);
        }
    }
}

1305. 两棵二叉搜索树中的所有元素

给你 root1root2 这两棵二叉搜索树。

请你返回一个列表,其中包含 两棵树 中的所有整数并按 升序 排序。.

示例 1:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TcACeY30-1588937561408)(https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2019/12/29/q2-e1.png)]

输入:root1 = [2,1,4], root2 = [1,0,3]
输出:[0,1,1,2,3,4]

解答:

class Solution {

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

    public List<Integer> getAllElements(TreeNode root1, TreeNode root2) {
        inorder(root1);
        inorder(root2);
        //排序
        Collections.sort(list);
        List<Integer> res=new ArrayList<>(list);
        return res;
    }

    //中序遍历的结果较有序,时间更少
    public void inorder(TreeNode root){
        if(root!=null){
            inorder(root.left);
            list.add(root.val);
            inorder(root.right);
        }
    }
}

1315. 祖父节点值为偶数的节点和

给你一棵二叉树,请你返回满足以下条件的所有节点的值之和:

  • 该节点的祖父节点的值为偶数。(一个节点的祖父节点是指该节点的父节点的父节点。)

如果不存在祖父节点值为偶数的节点,那么返回 0

示例:

img

输入:root = [6,7,8,2,7,1,3,9,null,1,4,null,null,null,5]
输出:18
解释:图中红色节点的祖父节点的值为偶数,蓝色节点为这些红色节点的祖父节点。

解答:

class Solution {

    int sum=0;

    public int sumEvenGrandparent(TreeNode root) {
        if(root==null)
            return 0;
        if(root.val%2==0){
            //左节点不为空
            if(root.left!=null){
                sum+=root.left.left==null?0:root.left.left.val;
                sum+=root.left.right==null?0:root.left.right.val;
            }
            //右节点不为空
            if(root.right!=null){
                sum+=root.right.left==null?0:root.right.left.val;
                sum+=root.right.right==null?0:root.right.right.val;
            }
        }
        sumEvenGrandparent(root.left);
        sumEvenGrandparent(root.right);
        return sum;
    }
}

1325. 删除给定值的叶子节点

给你一棵以 root 为根的二叉树和一个整数 target ,请你删除所有值为 target叶子节点

注意,一旦删除值为 target 的叶子节点,它的父节点就可能变成叶子节点;如果新叶子节点的值恰好也是 target ,那么这个节点也应该被删除。

也就是说,你需要重复此过程直到不能继续删除。

示例 1:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KsvXWQm3-1588937561409)(https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/01/16/sample_1_1684.png)]

输入:root = [1,2,3,2,null,2,4], target = 2
输出:[1,null,3,null,4]
解释:
上面左边的图中,绿色节点为叶子节点,且它们的值与 target 相同(同为 2 ),它们会被删除,得到中间的图。
有一个新的节点变成了叶子节点且它的值与 target 相同,所以将再次进行删除,从而得到最右边的图。

解答:

    //类似814题
    public TreeNode removeLeafNodes(TreeNode root, int target) {
        if(root!=null){
            if(root.val==target&&root.left==null&&root.right==null)
                return null;
            TreeNode nodeL;
            TreeNode nodeR;
            if((nodeL=removeLeafNodes(root.left,target))==null)
                root.left=null;
            if((nodeR=removeLeafNodes(root.right,target))==null)
                root.right=null;
            if(root.val==target&&nodeL==null&&nodeR==null)
                return null;
        }
        return root;
    }

1367. 二叉树中的列表

给你一棵以 root 为根的二叉树和一个 head 为第一个节点的链表。

如果在二叉树中,存在一条一直向下的路径,且每个点的数值恰好一一对应以 head 为首的链表中每个节点的值,那么请你返回 True ,否则返回 False

一直向下的路径的意思是:从树中某个节点开始,一直连续向下的路径。

示例 1:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5p4Peesi-1588937561410)(https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/02/29/sample_1_1720.png)]

输入:head = [4,2,8], root = [1,4,4,null,2,2,null,1,null,6,8,null,null,null,null,1,3]
输出:true
解释:树中蓝色的节点构成了与链表对应的子路径。

解答:

    public boolean isSubPath(ListNode head, TreeNode root) {
        if(root==null)
            return false;
        return isSub(head,root)||isSubPath(head, root.left)||isSubPath(head, root.right);
    }

    //以当前root为根节点能否匹配
    public boolean isSub(ListNode head,TreeNode root){
        //链表为空,匹配成功
        if(head==null)
            return true;
        //链表不为空但是root为空,代表失败了
        if(root==null)
            return false;
        //节点值不同,失败
        if(root.val!=head.val)
            return false;
        //当前节点匹配成功,匹配下一个,左右子树有一边成功即可
        return isSub(head.next,root.left)||isSub(head.next,root.right);
    }

1379. 找出克隆二叉树中的相同节点

给你两棵二叉树,原始树 original 和克隆树 cloned,以及一个位于原始树 original 中的目标节点 target

其中,克隆树 cloned 是原始树 original 的一个 副本

请找出在树 cloned 中,与 target 相同 的节点,并返回对该节点的引用(在 C/C++ 等有指针的语言中返回 节点指针,其他语言返回节点本身)。

注意:

  1. 不能 对两棵二叉树,以及 target 节点进行更改。
  2. 只能 返回对克隆树 cloned 中已有的节点的引用。

**进阶:**如果树中允许出现值相同的节点,你将如何解答?

示例 1:

img
输入: tree = [7,4,3,null,null,6,19], target = 3
输出: 3
解释: 上图画出了树 original 和 cloned。target 节点在树 original 中,用绿色标记。答案是树 cloned 中的黄颜色的节点(其他示例类似)。

解答:

    public final TreeNode getTargetCopy(final TreeNode original, final TreeNode cloned, final TreeNode target) {
        //是克隆树,一个节点不为空,另一个一定不为空
        if(original!=null){
            if(original==target){
                return cloned;
            }
            //没找到,分别在左子树找
            TreeNode res=getTargetCopy(original.left,cloned.left,target);
            if(res!=null)
                return res;
            //左子树也没有,返回右子树寻找的结果
            return getTargetCopy(original.right,cloned.right,target);
        }
        return original;
    }

1430. Check If a String Is a Valid Sequence from Root to Leaves Path in a Binary Tree

Given a binary tree where each path going from the root to any leaf form a valid sequence, check if a given string is a valid sequence in such binary tree.

We get the given string from the concatenation of an array of integers arr and the concatenation of all values of the nodes along a path results in a sequence in the given binary tree.

Example 1:

img

Input: root = [0,1,0,0,1,0,null,null,1,0,0], arr = [0,1,0,1]
Output: true
Explanation: 
The path 0 -> 1 -> 0 -> 1 is a valid sequence (green color in the figure). 
Other valid sequences are: 
0 -> 1 -> 1 -> 0 
0 -> 0 -> 0

Example 2:

img

Input: root = [0,1,0,0,1,0,null,null,1,0,0], arr = [0,0,1]
Output: false 
Explanation: The path 0 -> 0 -> 1 does not exist, therefore it is not even a sequence.

Example 3:

img

Input: root = [0,1,0,0,1,0,null,null,1,0,0], arr = [0,1,1]
Output: false
Explanation: The path 0 -> 1 -> 1 is a sequence, but it is not a valid sequence.

解答:

    public boolean isValidSequence(TreeNode root, int[] arr) {
        return isValid(root,arr,0);
    }

    //辅助函数,前序遍历dfs
    public boolean isValid(TreeNode root,int[] arr,int index){
        if(root==null||index==arr.length)//节点空或数组匹配完成但节点非空,匹配失败
            return false;
        if(root.val!=arr[index])//节点值和数组值不同,匹配失败
            return false;
        if(root.left==null&&root.right==null&&index==arr.length-1)//当前是叶子节点,并且数组匹配完毕
            return true;
        //左右子树任意一边匹配成功即可
        return isValid(root.left,arr,index+1)||isValid(root.right,arr,index+1);
    }

面试题 04.02. 最小高度树

给定一个有序整数数组,元素各不相同且按升序排列,编写一个算法,创建一棵高度最小的二叉搜索树。

解答:和108题一样。


面试题 04.03. 特定深度节点链表

给定一棵二叉树,设计一个算法,创建含有某一深度上所有节点的链表(比如,若一棵树的深度为 D,则会创建出 D 个链表)。返回一个包含所有深度的链表的数组。

示例:

输入:[1,2,3,4,5,null,7,8]

        1
       /  \ 
      2    3
     / \    \ 
    4   5    7
   /
  8

输出:[[1],[2,3],[4,5,7],[8]]

解答:

    //思路跟二叉树层序遍历一样
	public ListNode[] listOfDepth(TreeNode root) {
        List<ListNode> result=new ArrayList<>();
        //保存节点
        List<TreeNode> trees=new ArrayList<>();
        //保存临时结果
        ListNode temp;
        if(root!=null){
            trees.add(root);
            while(!trees.isEmpty()){
                //计算当前层节点数,按数量全部出队,再将其左右节点依次入队
                int n=trees.size();
                temp=new ListNode(-1);
                ListNode cur=temp;
                for(int i=0;i<n;i++){
                    TreeNode remove=trees.remove(0);
                    cur.next=new ListNode(remove.val);
                    cur=cur.next;
                    //出队节点的左右节点不为空就入队
                    if(remove.left!=null)
                        trees.add(remove.left);
                    if(remove.right!=null)
                        trees.add(remove.right);
                }
                //添加到结果集
                result.add(temp.next);
            }
        }
        ListNode[] res=new ListNode[result.size()];
        for(int i=0;i<res.length;i++)
            res[i]=result.get(i);
        return res;
    }

面试题 04.04. 检查平衡性

实现一个函数,检查二叉树是否平衡。在这个问题中,平衡树的定义如下:任意一个节点,其两棵子树的高度差不超过 1。

解答:和110题一样。


面试题 04.05. 合法二叉搜索树

实现一个函数,检查一棵二叉树是否为二叉搜索树。

解答:和98题一样。


面试题 04.06. 后继者

设计一个算法,找出二叉搜索树中指定节点的“下一个”节点(也即中序后继)。

如果指定节点没有对应的“下一个”节点,则返回null

示例 1:

输入: root = [2,1,3], p = 1

  2
 / \
1   3

输出: 2

解答:

class Solution {

    //保存中序节点序列
    List<TreeNode> list=new ArrayList<>();

    public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
        inorder(root);
        for(int i=0;i<list.size()-1;i++){
            if(list.get(i)==p)
                return list.get(i+1);
        }
        return null;
    }


    //中序遍历保存升序序列
    public void inorder(TreeNode root){
        if(root!=null){
            inorder(root.left);
            list.add(root);
            inorder(root.right);
        }
    }
}

面试题 04.08. 首个共同祖先

设计并实现一个算法,找出二叉树中某两个节点的第一个共同祖先。不得将其他的节点存储在另外的数据结构中。注意:这不一定是二叉搜索树。

解答:和236题一样。


面试题 04.10. 检查子树

检查子树。你有两棵非常大的二叉树:T1,有几万个节点;T2,有几万个节点。设计一个算法,判断 T2 是否为 T1 的子树。

如果 T1 有这么一个节点 n,其子树与 T2 一模一样,则 T2 为 T1 的子树,也就是说,从节点 n 处把树砍断,得到的树与 T2 完全相同。

解答:和572题一样。


面试题 04.12. 求和路径

给定一棵二叉树,其中每个节点都含有一个整数数值(该值或正或负)。设计一个算法,打印节点数值总和等于某个给定值的所有路径的数量。注意,路径不一定非得从二叉树的根节点或叶节点开始或结束,但是其方向必须向下(只能从父节点指向子节点方向)。

解答:和437题一样。


面试题 17.12. BiNode

二叉树数据结构TreeNode可用来表示单向链表(其中left置空,right为下一个链表节点)。实现一个方法,把二叉搜索树转换为单向链表,要求值的顺序保持不变,转换操作应是原址的,也就是在原始的二叉搜索树上直接修改。返回转换后的单向链表的头节点。

解答:和897题一样。


面试题07. 重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

解答:和106题一样。


面试题26. 树的子结构

输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)

B是A的子结构, 即 A中有出现和B相同的结构和节点值。

解答:

    //和572题类似
    public boolean isSubStructure(TreeNode s, TreeNode t) {
        if(s==null||t==null)
            return false;
        //以当前节点为根,或者在左右子树中继续寻找
        return isSame(s,t)||isSubStructure(s.left,t)||isSubStructure(s.right,t);
    }

    //判断两个分别以s和t作为根节点的树是否相同
    public boolean isSame(TreeNode s,TreeNode t){
        if(s==null&&t!=null)
            return false;
        if(t==null)
            return true;
        //根节点值不同为false
        if(s.val!=t.val)
            return false;
        //比较对应的左子树和右子树
        return isSame(s.left,t.left)&&isSame(s.right,t.right);
    }

面试题27. 二叉树的镜像

请完成一个函数,输入一个二叉树,该函数输出它的镜像。

解答:和226题一样。


面试题28. 对称的二叉树

请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。

解答:和101题一样。


面试题32 - I. 从上到下打印二叉树

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

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

3

/
9 20
/
15 7
返回:

[3,9,20,15,7]

解答:

    public int[] levelOrder(TreeNode root) {
        //保存结果集
        List<Integer> result=new ArrayList<>();
        //保存节点
        List<TreeNode> trees=new ArrayList<>();
        //保存临时结果
        if(root!=null){
            trees.add(root);
            while(!trees.isEmpty()){
                //计算当前层节点数,按数量全部出队,再将其左右节点依次入队
                int n=trees.size();
                for(int i=0;i<n;i++){
                    TreeNode remove=trees.remove(0);
                    result.add(remove.val);
                    //出队节点的左右节点不为空就入队
                    if(remove.left!=null)
                        trees.add(remove.left);
                    if(remove.right!=null)
                        trees.add(remove.right);
                }
            }
        }
        int[] res=new int[result.size()];
        for(int i=0;i<res.length;i++){
            res[i]=result.get(i);
        }
        return res;
    }

面试题32 - II. 从上到下打印二叉树 II

从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

解答:和102题一样。


面试题32 - III. 从上到下打印二叉树 III

请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

解答:和103题一样。


面试题34. 二叉树中和为某一值的路径

输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。

解答:和113题一样。


面试题54. 二叉搜索树的第k大节点

给定一棵二叉搜索树,请找出其中第k大的节点。

示例 1:

输入: root = [3,1,4,null,2], k = 1
   3
  / \
 1   4
  \
   2
输出: 4

解答:

class Solution {

    ArrayList<Integer> list=new ArrayList<>();

    public int kthLargest(TreeNode root, int k) {
        inorder(root);
        return list.get(list.size()-k);
    }

    //中序遍历,结果从小到大保存
    public void inorder(TreeNode root){
        if(root!=null){
            inorder(root.left);
            list.add(root.val);
            inorder(root.right);
        }
    }

}

面试题55 - I. 二叉树的深度

输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。

解答:和104题一样。


面试题55 - II. 平衡二叉树

输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

解答:和110题一样。


面试题68 - I. 二叉搜索树的最近公共祖先

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

解答:和235题一样。


面试题68 - II. 二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

解答:和236题一样。

猜你喜欢

转载自blog.csdn.net/qq_41112238/article/details/106004563
今日推荐