Skip to content

Latest commit

 

History

History
1337 lines (1193 loc) · 36.4 KB

05二叉树和递归.md

File metadata and controls

1337 lines (1193 loc) · 36.4 KB
章节 典型题目 相关题目 更多扩展练习 难题推荐
5-1 二叉树天然的递归结构 104 111
5-2 一个简单的二叉树问题引发的血案 Invert Binary Tree 226 100 101 222 110
5-3 注意递归的终止条件 Path Sum 112 111 404
5-4 定义递归问题 Binary Tree Path 257 113 129
5-5 稍复杂的递归逻辑 Path Sum III 437 [无] 785
5-6 二分搜索树中的问题 Lowest Common Ancestor of a Binary Search Tree 235 783 98 450 108 230 236 530 99
补充1 更多二叉树的问题 [无] [无] 109 105 106 889 173* 863 865 872 894 897 95 87
补充2 二叉树相关的所有操作 [无] [无] [无] [无]
补充3 二分搜索树的基本操作 [无] [无] [无] [无]

二叉树和递归

二叉树天然的递归结构

104

104 Maximum Depth of Binary Tree

  • 问题:

求一棵二叉树的最大深度。

  • 解题:
public int maxDepth(TreeNode root) {
    if(root==null){
        return 0;
    }
    return Math.max(maxDepth(root.left),maxDepth(root.right))+1;
}

111

111 Minimum Depth of Binary Tree

public int minDepth(TreeNode root) {
    if(root==null) {
        return 0;
    }
    /**
     * 针对
     *     1
     *     \
     *      2
     *  的情况
     */
    if(root.left==null){
        return minDepth(root.right)+1;
    }
    /**
     * 针对
     *      1
     *     /
     *    2
     * 的情况
     */
    if(root.right==null){
        return minDepth(root.left)+1;
    }
    return Math.min(minDepth(root.left),minDepth(root.right))+1;
}

一个简单的二叉树问题引发的血案

226

226. Invert Binary Tree

  • 问题:

反转一棵二叉树。

  • 示例:
  • 解题:
public TreeNode invertTree(TreeNode root) {
    if(root==null){
        return null;
    }
    invertTree(root.left);
    invertTree(root.right);

    //交换root的左右节点
    TreeNode tmp=root.left;
    root.left=root.right;
    root.right=tmp;
    return root;
}

100

100 Same Tree

public boolean isSameTree(TreeNode p, TreeNode q) {
    if(p==null && q==null){
        return true;
    }
    if(p==null && q!=null){
        return false;
    }
    if(p!=null && q==null){
        return false;
    }
    //注意p.q是对象,比较的是节点的值
    if(p.val!=q.val){
        return false;
    }
    return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
}

101

101 Symmetric Tree

public boolean isSymmetric(TreeNode root) {
    if(root==null){
        return true;
    }
    return isSymmetric(root.left,root.right);
}

//判断两棵树是否对称
private boolean isSymmetric(TreeNode p,TreeNode q){
    if(p==null && q==null){
        return true;
    }
    if(p==null && q!=null){
        return false;
    }
    if(p!=null && q==null){
        return false;
    }
    //注意p.q是对象,比较的是节点的值
    if(p.val!=q.val){
        return false;
    }

    return isSymmetric(p.left,q.right) && isSymmetric(p.right,q.left);
}

222

222 Count Complete Tree Nodes

/**
 * 思路:
 * 如果用常规的解法一个个遍历,就是O(n)时间复杂度 ,会不通过。
 * 因为是完全二叉树,满二叉树有一个性质是节点数等于2^h-1,h为高度,
 * 所以可以这样判断节点的左右高度是不是一样,如果是一样说明是满二叉树,
 */
public int countNodes(TreeNode root) {
    //空树
    if(root==null){
        return 0;
    }
    //只有一个节点
    if(root.left==null && root.right==null){
        return 1;
    }
    int l=getLeftHeight(root);
    int r=getRightHeight(root);
    if(l==r){
        return (1<<r)-1; 
        //(1<<r)表示的是 2^r ,也就是有l层满二叉树中节点的数目是 (2^r-1)
    }else{
        return countNodes(root.left)+countNodes(root.right)+1;
    }
}

private int getLeftHeight(TreeNode root){
    int height=0;
    while(root!=null){
        height++;
        root=root.left;
    }
    return height;
}

private int getRightHeight(TreeNode root){
    int height=0;
    while(root!=null){
        height++;
        root=root.right;
    }
    return height;
}

110

110 Balanced Binary Tree

public boolean isBalanced(TreeNode root) {
    if(root==null){
        return true;
    }
    if(root.left==null && root.right==null){
        return true;
    }
    //获取该树的左右子树的深度
    int l=getTreeDepth(root.left);
    int r=getTreeDepth(root.right);
    if(Math.abs(l-r)>1){
        return false;
    }
    return isBalanced(root.left) && isBalanced(root.right);
}

//得到一棵树的深度
private int getTreeDepth(TreeNode root){
    if(root==null){
        return 0;
    }
    return Math.max(getTreeDepth(root.left),getTreeDepth(root.right))+1;
}

注意递归的终止条件

112

112 Path Sum

  • 问题:
  • 解题:
public boolean hasPathSum(TreeNode root, int sum) {
    //注意递归结束的条件
    if(root==null){
        //如果是一个空树,那么是不可能有路径的
        return false;
    }
    if(root.left==null && root.right==null){
        //如果根节点是叶子节点
        return root.val==sum;
    }
    return hasPathSum(root.left,sum-root.val) || hasPathSum(root.right,sum-root.val);
}

111

111 Minimum Depth of Binary Tree

public int minDepth(TreeNode root) {
    if(root==null) {
        return 0;
    }
    /**
     * 针对
     *     1
     *     \
     *      2
     *  的情况
     */
    if(root.left==null){
        return minDepth(root.right)+1;
    }
    /**
     * 针对
     *      1
     *     /
     *    2
     * 的情况
     */
    if(root.right==null){
        return minDepth(root.left)+1;
    }
    return Math.min(minDepth(root.left),minDepth(root.right))+1;
}

404

404 Sum of Left Leaves

public int sumOfLeftLeaves(TreeNode root) {
    if(root==null){
        return 0;
    }
    if(root.left!=null && (root.left.left==null && root.left.right==null)){
        return root.left.val+sumOfLeftLeaves(root.right);
    }
    return sumOfLeftLeaves(root.left)+sumOfLeftLeaves(root.right);
}

定义递归问题

257

257 Binary Tree Paths

  • 问题:
  • 解题:

递归的思路:将一棵树拆成 root->左子树对应字符串 + root->右子树对应的字符串

在左子树进行相同的操作:

在右子树进行相同的操作:

public List<String> binaryTreePaths(TreeNode root) {
    List<String> ret=new ArrayList<>();
    if(root==null){
        return ret;
    }
    if(root.left==null && root.right==null){
        ret.add(root.val+"");
        return ret;
    }
    List<String> leftS=binaryTreePaths(root.left);
    for(String s:leftS){
        ret.add(root.val+"->"+s);
    }
    List<String> rightS=binaryTreePaths(root.right);
    for(String s:rightS){
        ret.add(root.val+"->"+s);
    }
    return ret;
}

113

113 Path Sum II

  • 解法一:
public List<List<Integer>> pathSum(TreeNode root, int sum) {
    //将 findPath所得的结果转换为适当的格式返回
    List<List<Integer>> res=new ArrayList<>();
    List<String> ret=findPath(root,sum);
    for(String str:ret){
        List<Integer> tmp=new ArrayList<>();
        String[] val=str.split("->");
        for(String v:val){
            Integer i=Integer.parseInt(v);
            tmp.add(i);
        }
        res.add(tmp);
    }
    return res;
}

//找从根节点到叶子节点的路径和为sum的路径
private List<String> findPath(TreeNode root,int sum){
    List<String> paths = new ArrayList<>();
    if(root == null){
        return paths;
    }
    if(root.left == null && root.right == null){
        if(root.val==sum){
            paths.add(root.val+"");
            return paths;
        }
    }
    List<String> leftPath=findPath(root.left,sum-root.val);
    for (String path : leftPath) {
        paths.add(root.val + "->" + path);
    }
    List<String> rightPath=findPath(root.right,sum-root.val);
    for (String path : rightPath) {
        paths.add(root.val + "->" + path);
    }
    return paths;
}
  • 解法二:
private List<List<Integer>> res;

public List<List<Integer>> pathSum(TreeNode root, int sum) {
    res=new ArrayList<>();
    if(root==null){
        return res;
    }
    List<Integer> p=new ArrayList<>();
    dfs(root,0,sum,p);
    return res;
}

private void dfs(TreeNode node,int tSum, int sum,List<Integer> p){
    if(node==null){
        return;
    }
    p.add(node.val);
    tSum+=node.val;

    //到达叶子节点并且路径值和为sum,这说明找到了一条路径,将值存入
    if(node.left==null && node.right==null){
        if(tSum==sum){
            res.add(new ArrayList<>(p));
        }
    }else{
        if(node.left!=null){
            dfs(node.left,tSum,sum,p);
        }
        if(node.right!=null){
            dfs(node.right,tSum,sum,p);
        }
    }
    p.remove(p.size()-1);
    tSum-=node.val;
    return;
}

129

129 Sum Root to Leaf Numbers

public int sumNumbers(TreeNode root) {
    List<String> ret=findPath(root);
    int sum=0;
    for(String ele:ret){
        Integer i=Integer.parseInt(ele);
        sum+=i;
    }
    return sum;
}

//查找所有到叶子结点的路径
private List<String> findPath(TreeNode root){
    List<String> ret=new ArrayList<>();
    if(root==null){
        return ret;
    }
    if(root.left==null && root.right==null){
        ret.add(root.val+"");
        return ret;
    }
    List<String> leftPath=findPath(root.left);
    for(String path:leftPath){
        ret.add(root.val+""+path);
    }
    List<String> rightPath=findPath(root.right);
    for(String path:rightPath){
        ret.add(root.val+""+path);
    }
    return ret;
}

稍复杂的递归逻辑

437

437 Path Sum III

  • 问题:

给出一棵二叉树以及一个数字sum,判断在这棵二叉树上存在多少条路径,其路径上的所有节点和为sum。

其中路径不一定要起始于根节点;终止于叶子结点。

路径可以从任意节点开始,但是只能是向下走的。

  • 示例:
  • 解题:
//以root为根节点的二叉树中,寻找和为sum的路径,返回这样的路径的个数
public int pathSum(TreeNode root, int sum) {
    if(root==null){
        return 0;
    }
    int res=findPath(root,sum);
    res+=pathSum(root.left,sum);
    res+=pathSum(root.right,sum);
    return res;
}

//以node为根节点的二叉树中,寻找包含node的路径,和为sum
//返回这样的路径个数
private int findPath(TreeNode node,int sum){
    if(node==null){
        return 0;
    }
    int res=0;
    if(node.val==sum){
        res+=1;
    }
    res+=findPath(node.left,sum-node.val);
    res+=findPath(node.right,sum-node.val);
    return res;
}

785

785 Is Graph Bipartite?

/**
 * 思路:
 * 首先检查该结点是否已经被检查,如果是,则看看是否能满足要求;
 * 否则就给结点分组,并且采用DFS的策略对和其直接或者间接相连的所有结点进行分组。
 * 整个过程中如果发现冲突就提前返回false;否则在最后返回true。
 */
private int[] checked;

public boolean isBipartite(int[][] graph) {
    checked=new int[graph.length];
    for(int i=0;i<checked.length;i++){
        checked[i]=-1;
    }
    for(int i=0;i<graph.length;i++){
        if(checked[i]==-1){
            if(!check(graph,i,0)){
                return false;
            }
        }
    }
    return true;
}

/**
 * @param graph
 * @param index 对应的结点下标
 * @param group 分组标号,数值为0和1,group初始值为0,1-group值就变成1
 * @return
 */
private boolean check(int[][] graph,int index,int group){
    if(checked[index]!=-1){
        //首先检查该结点是否已经被检查,如果是,则看看是否能满足要求;
        return checked[index]==group;
    }
    checked[index]=group;
    //遍历与该结点相连的其他结点
    for(int next:graph[index]){
        if(!check(graph,next,1-group)){
            return false;
        }
    }
    return true;
}

二分搜索树中的问题

235

235 Lowest Common Ancestor of a Binary Search Tree

  • 问题
  • 解题:

p,q都是该二分搜索树的节点,对于p,q节点的公共祖先节点,分为3个情况:

(1) p,q值都小于node,则他们的公共祖先在node的左子树中

(2) p,q值都大于node,则他们的公共祖先在node的右子树中

(3) node在p,q之间的,则他们的公共祖先就是node

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    if(root==null){
        return null;
    }
    if(p.val<root.val && q.val<root.val){
        return lowestCommonAncestor(root.left,p,q);
    }
    if(p.val>root.val && q.val>root.val){
        return lowestCommonAncestor(root.right,p,q);
    }
    return root;
}

783

783 Minimum Distance Between BST Nodes

public int minDiffInBST(TreeNode root) {
    inOrder(root);
    int min=Integer.MAX_VALUE;
    for(int i=0;i<inOrder.size()-1;i++){
        Integer num1=inOrder.get(i);
        Integer num2=inOrder.get(i+1);
        min=Math.min(min,Math.abs(num1-num2));
    }
    return min;
}

private List<Integer> inOrder=new ArrayList<>();
private void inOrder(TreeNode root){
    if(root==null){
        return;
    }
    inOrder(root.left);
    inOrder.add(root.val);
    inOrder(root.right);
}

98

98 Validate Binary Search Tree

//注意数值范围的问题,有的节点的值超过了int类型的范围
public boolean isValidBST(TreeNode root) {
    return isValid(root,Long.MIN_VALUE,Long.MAX_VALUE);
}

//判断左子树最大值为leftMax,右子树最小值为rightMin的树是否是BST
public boolean isValid(TreeNode root,long leftMax,long rightMin){
    if(root==null){
        return true;
    }
    if(root.left==null && root.right==null){
        return true;
    }
    if(root.val<=leftMax || root.val>=rightMin){
        return false;
    }
    return isValid(root.left,leftMax,root.val) && isValid(root.right,root.val,rightMin);
}

450

450. Delete Node in a BST

public TreeNode deleteNode(TreeNode root, int key) {
    if (root == null){
        return root;
    }
    //删除的是根结点
    if(root.val==key){
        //右子树为空,那么就直接删除该根节点,返回右子树
        if(root.right==null){
            TreeNode node=root.left;
            root=node;
            return root;
        }else{
            //右子树不为空,则将该右子树的最小值,代替根结点的值
            TreeNode right=root.right;
            while(right.left!=null){
                right=right.left;
            }
            int tmp=root.val;
            root.val=right.val;
            right.val=tmp;
        }
    }
    root.left=deleteNode(root.left,key);
    root.right=deleteNode(root.right,key);
    return root;
}

108

108 Convert Sorted Array to Binary Search Tree

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

private TreeNode sortedArrayToBST(int[] nums,int start,int end) {
    if(start>end){
        return null;
    }
    int mid=start+(end-start)/2;
    //将中间结点作为根结点,
    //这样其左子树元素为[strat...mid-1]
    //右子树元素为[mid+1...end]
    TreeNode root=new TreeNode(nums[mid]);
    if(start==end){
        return root;
    }
    root.left=sortedArrayToBST(nums,start,mid-1);
    root.right=sortedArrayToBST(nums,mid+1,end);
    return root;
}

230

230 Kth Smallest Element in a BST

private int index=0;
private TreeNode tmp;

//k是从1开始的
//k始终有效
public int kthSmallest(TreeNode root, int k) {
    inOrder(root,k);
    return tmp.val;
}

//利用BST树中序遍历的性质,得到第k个元素,就停止中序遍历。
public void inOrder(TreeNode root,int k){
   if(root==null){
       return;
   }
   inOrder(root.left,k);
   index++;
   if(index==k){
       tmp=root;
       return;
   }
   inOrder(root.right,k);
}

236

236 Lowest Common Ancestor of a Binary Tree

// 在root中寻找p和q
// 如果p和q都在root所在的二叉树中, 则返回LCA
// 如果p和q只有一个在root所在的二叉树中, 则返回p或者q
// 如果p和q均不在root所在的二叉树中, 则返回NULL
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    if(root==null){
        return null;
    }
    //根节点是p或者q,则就返回该根节点就可以了
    if(root==p || root==q){
        return root;
    }
    //看看root的最子树是否包含p,q
    TreeNode left=lowestCommonAncestor(root.left,p,q);
    TreeNode right=lowestCommonAncestor(root.right,p,q);
    //p,q的最小公共祖先
    //要么是root
    //要么是在root的左子树
    //要么是在root的右子树
    if(left!=null && right!=null){
        return root;
    }
    if(left!=null){
        return left;
    }
    if(right!=null){
        return right;
    }
    return null;
}

更多二叉树的问题

109

109 Convert Sorted List to Binary Search Tree

  • 思路一:参考108题,但是效率太低。
public TreeNode sortedListToBST(ListNode head) {
    if(head==null){
        return null;
    }
    return sortedListToBST(head,0,getLength(head)-1);
}

private TreeNode sortedListToBST(ListNode head,int start,int end){
    if(start>end){
        return null;
    }
    int mid=start+(end-start)/2;
    TreeNode root=new TreeNode(getElement(head,mid));
    if(start==end){
        return root;
    }
    root.left=sortedListToBST(head,start,mid-1);
    root.right=sortedListToBST(head,mid+1,end);
    return root;
}

private int getLength(ListNode head){
    int count=0;
    ListNode cur=head;
    while(cur!=null){
        count++;
        cur=cur.next;
    }
    return count;
}

//按照index获取链表中数据
private int getElement(ListNode head,int index){
   int i=0;
   ListNode cur=head;
   while(cur!=null && i!=index){
       cur=cur.next;
       i++;
   }
   return cur.val;
}
  • 思路二:
private ListNode cur;
public TreeNode sortedListToBST(ListNode head) {
    if (head == null) {
        return null;
    }
    cur=head;
    return buildBST(0,getLength(head)-1);
}

private TreeNode buildBST(int start,int end){
    if(start>end){
        return null;
    }
    int mid=start+(end-start)/2;
    TreeNode left=buildBST(start,mid-1);

    TreeNode root=new TreeNode(cur.val);
    cur=cur.next;

    TreeNode right=buildBST(mid+1,end);

    root.left=left;
    root.right=right;
    return root;
}

private int getLength(ListNode head){
    int count=0;
    ListNode cur=head;
    while(cur!=null){
        count++;
        cur=cur.next;
    }
    return count;
}

105

105 Construct Binary Tree from Preorder and Inorder Traversal

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

private TreeNode buildTree(int[] preorder,int[] inorder,int preStart,int preEnd,int inStart,int inEnd){
    if(preStart>preEnd || inStart>inEnd){
        return null;
    }
    TreeNode root=new TreeNode(preorder[preStart]);
    int mid=0;
    for(int i=inStart;i<=inEnd;i++){
        if(inorder[i]==preorder[preStart]){
            mid=i;
            break;
        }
    }
    root.left=buildTree(preorder,inorder,preStart+1,preStart+(mid-inStart),inStart,mid-1);
    root.right=buildTree(preorder,inorder,preStart+(mid-inStart)+1,preEnd,mid+1,inEnd);
    return root;
}

106

106 Construct Binary Tree from Inorder and Postorder Traversal

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

private TreeNode buildTree(int[] inorder,int[] postorder,int inStart,int inEnd,int postStart,int postEnd){
    if(inStart>inEnd || postStart>postEnd){
        return null;
    }
    TreeNode root=new TreeNode(postorder[postEnd]);
    int mid=0;
    for(int i=inStart;i<=inEnd;i++){
        if(inorder[i]==postorder[postEnd]){
            mid=i;
            break;
        }
    }
    root.left=buildTree(inorder,postorder,inStart,mid-1,postStart,postStart+(mid-inStart)-1);
    root.right=buildTree(inorder,postorder,mid+1,inEnd,postStart+(mid-inStart),postEnd-1);
    return root;
}

889

889 Construct Binary Tree from Preorder and Postorder Traversal

public TreeNode constructFromPrePost(int[] pre, int[] post) {
    return constructFromPrePost(pre,post,0,pre.length-1,0,post.length-1);
}

private TreeNode constructFromPrePost(int[] pre, int[] post,int preStart,int preEnd,int postStart,int postEnd){
    if(preStart>preEnd || postStart>postEnd){
        return null;
    }
    TreeNode root=new TreeNode(pre[preStart]);
    if(preStart==preEnd){
        return root;
    }

    //左子树根结点
    int k;
    for(k=postStart;k<postEnd;k++){
        if(post[k]==pre[preStart+1]){
            break;
        }
    }
    root.left=constructFromPrePost(pre,post,preStart+1,preStart+k-postStart+1,postStart,k);
    root.right=constructFromPrePost(pre,post,preStart+k-postStart+2,preEnd,k+1,postEnd-1);
    return root;
}

173

173 Binary Search Tree Iterator

/**
 * 思路一:
 * 就是利用BST的中序遍历性质(递归思路)
 * 空间复杂度:O(n)
 * 时间复杂度: next() --> O(1)
 *              hasNext() --> O(1)
 */
class BSTIterator {
    private List<Integer> data=new ArrayList<>();
    private int nextIndex;

    public BSTIterator(TreeNode root) {
        inOrder(root);
        nextIndex=0;
    }

    private void inOrder(TreeNode root){
        if(root==null){
            return;
        }
        inOrder(root.left);
        data.add(root.val);
        inOrder(root.right);
    }

    /** @return the next smallest number */
    public int next() {
        return data.get(nextIndex++);
    }

    /** @return whether we have a next smallest number */
    public boolean hasNext() {
        return nextIndex<data.size()-1;
    }
}
/**
 * 思路二:非递归方式
 * 空间复杂度:O(h)
 * 时间复杂度:next() --> O(1)
 *             hasNext() --> O(h)
 */
class BSTIterator{
    private Stack<TreeNode> myStack;

    public BSTIterator(TreeNode root) {
        myStack=new Stack<>();
        TreeNode node = root;
        while(node != null){
            myStack.push(node);
            node = node.left;
        }
    }

    /** @return the next smallest number */
    public int next() {
        assert(hasNext());
        TreeNode retNode = myStack.pop();

        TreeNode node = retNode.right;
        while(node != null){
            myStack.push(node);
            node = node.left;
        }
        return retNode.val;
    }

    /** @return whether we have a next smallest number */
    public boolean hasNext() {
        return !myStack.isEmpty();
    }
}

863

863 All Nodes Distance K in Binary Tree

/**
 * 解题思路:先从根dfs一遍,将树变成图。之后从要求的点bfs即可。
 */
//使用集合数组存储图
private Vector<Integer>[] G;

//用于判断图中某一个结点,是否被访问
private boolean[] isVisited;

//通过dfs操作将该二叉树,转化为一个无向图
private void dfs(TreeNode root){
    if(root==null){
        return;
    }
    int v=root.val;
    if(root.left!=null){
        int w=root.left.val;
        G[v].add(w);
        G[w].add(v);
        dfs(root.left);
    }
    if(root.right!=null){
        int w=root.right.val;
        G[v].add(w);
        G[w].add(v);
        dfs(root.right);
    }
}

public List<Integer> distanceK(TreeNode root, TreeNode target, int K) {
    List<Integer> res=new ArrayList<>();
    if(root==null){
        return res;
    }
    if(K==0){
        res.add(target.val);
        return res;
    }
    G=(Vector<Integer>[])new Vector[1005];
    for(int i=0;i<1005;i++){
        G[i]=new Vector<>();
    }
    isVisited=new boolean[1005];
    //将二叉树转化为获取图
    dfs(root);

    //从target开始对图进行广度优先遍历
    //Pair<Integer,Integer>存的是<顶点,从target到该顶点的距离>
    Queue<Pair<Integer,Integer>> queue=new LinkedList<>();
    queue.add(new Pair<>(target.val,0));
    isVisited[target.val]=true;
    while(!queue.isEmpty()){
        Pair<Integer,Integer> pair=queue.poll();
        int v=pair.getKey();
        int distance=pair.getValue();
        if(distance==K){
            res.add(v);
            continue;
        }
        //遍历与v相邻的顶点
        for(Integer w:G[v]){
            if(!isVisited[w]){
                queue.add(new Pair<>(w,distance+1));
                isVisited[w]=true;
            }
        }
    }
    return res;
}

865

865 Smallest Subtree with all the Deepest Nodes

/**
 * 思路:
 * 这个题的模型其实比较左右子树的高度,如果左右子树的高度相等,说明当前节点就是要求的。
 * 这个解释是这样的:必须包含所有的最大高度的叶子,左右叶子高度相等,所以必须包含当前节点。
 *
 * 当左子树高度>右子树高度的时候,要求的节点在左边;反之,在右边。
 * 所以,递归思路 + 一个pair。这个pair的思路是,保存了当前节点的深度和当前节点的最深子树节点。
 * pair就是< 当前节点的深度,当前节点的最深子树节点>
 */
public TreeNode subtreeWithAllDeepest(TreeNode root) {
    if(root==null){
        return null;
    }
    return getNode(root).getValue();
}

private Pair<Integer,TreeNode> getNode(TreeNode root){
    if(root==null){
        return new Pair<>(-1,null);
    }
    Pair<Integer,TreeNode> l=getNode(root.left);
    Pair<Integer,TreeNode> r=getNode(root.right);
    int leftChildDepth=l.getKey();
    int rightChildDepth=r.getKey();
    int depth=Math.max(leftChildDepth,rightChildDepth)+1;
    /**
     * 如果左右子树的高度相等,说明当前节点就是要求的。
     * 这个解释是这样的:必须包含所有的最大高度的叶子,左右叶子高度相等,所以必须包含当前节点。
     */
    TreeNode node= null;
    if(leftChildDepth==rightChildDepth){
        node = root;
    }else if(leftChildDepth>rightChildDepth){
         //当左子树高度>右子树高度的时候,要求的节点在左边;反之,在右边。
        node = l.getValue();
    }else if(leftChildDepth<rightChildDepth){
        node = r.getValue();
    }
    return new Pair<>(depth,node);
}

872

872 Leaf-Similar Trees

/**
 * 思路:直接求出叶子节点,放入指定集合中即可,然后进行比较
 */
public boolean leafSimilar(TreeNode root1, TreeNode root2) {
    List<Integer> res1=new ArrayList<>();
    List<Integer> res2=new ArrayList<>();
    getLeaves(root1,res1);
    getLeaves(root2,res2);
    if(res1.equals(res2)){
        return true;
    }
    return false;
}

private void getLeaves(TreeNode root,List<Integer> res){
    if(root==null){
        return;
    }
    if(root.left==null && root.right==null){
        res.add(root.val);
    }
    getLeaves(root.left,res);
    getLeaves(root.right,res);
}
  • 使用记忆化搜索改进
public List<TreeNode> allPossibleFBT(int N) {
    if (N % 2 == 0) {
        return  new ArrayList<>();
    }
    //记录<节点数,以该结点数所构造的二叉树的所有可能>
    List<TreeNode>[] memo=new ArrayList[N+1];
    for(int i=0;i<memo.length;i++){
        memo[i]=new ArrayList<>();
    }
    return allPossibleFBT(N,memo);
}

private List<TreeNode> allPossibleFBT(int N,List<TreeNode>[] memo){
    if(memo[N].size()!=0){
        return memo[N];
    }
    if(N==1){
        memo[1]=new ArrayList<>(Arrays.asList(new TreeNode(0)));
        return memo[1];
    }
    for(int i=1;i<N;i+=2){
        List<TreeNode> leftChild=allPossibleFBT(i);
        List<TreeNode> rightChild=allPossibleFBT(N-1-i);
        for(TreeNode leftNode:leftChild){
            for(TreeNode rightNode:rightChild){
                TreeNode root=new TreeNode(0);
                root.left=leftNode;
                root.right=rightNode;
                memo[N].add(root);
            }
        }
    }
    return memo[N];
}

894

894 All Possible Full Binary Trees

/**
 * 思路:
 * 现在考虑有个根节点,它的所有满二叉树组合为allPossibleFBT(N),
 * 左子树可能有的节点数目为1,2,…,i,…,N-1,
 * 同时右子树可能有的节点数目为N-1-1,N-2-1,…,N-i-1,…,1。
 * 那么我们可以分别得到左右子树的所有满二叉树的组合:
 * allPossibleFBT(i)和allPossibleFBT(N-i-1)。
 */
public List<TreeNode> allPossibleFBT1(int N) {
    List<TreeNode> res=new ArrayList<>();
    if(N==0){
        return res;
    }
    if(N==1){
        res.add(new TreeNode(0));
        return res;
    }
    //一个结点只允许两种情况:无节点或者两个节点
    for(int i=1;i<=N-1;i+=2){
        List<TreeNode> leftChild=allPossibleFBT1(i);
        List<TreeNode> rightChild=allPossibleFBT1(N-1-i);
        for(TreeNode leftNode:leftChild){
            for(TreeNode rightNode:rightChild){
                TreeNode root=new TreeNode(0);
                root.left=leftNode;
                root.right=rightNode;
                res.add(root);
            }
        }
    }
    return res;
}

897

897 Increasing Order Search Tree

/**
 * 思路一
 */
private int[] inorder=new int[200];
private int index;

public TreeNode increasingBST(TreeNode root) {
    if(root==null){
        return null;
    }
    inOrder(root);
    return buildBST(inorder,0,index-1);
}

private TreeNode buildBST(int[] arr,int start,int end){
    if(arr==null || arr.length==0 || start>end){
        return null;
    }
    TreeNode root=new TreeNode(arr[start]);
    root.left=null;
    root.right=buildBST(arr,start+1,end);
    return root;
}

private void inOrder(TreeNode root){
    if(root==null){
        return;
    }
    inOrder(root.left);
    inorder[index++]=root.val;
    inOrder(root.right);
}
/**
* 思路二
*/
private TreeNode cur;

public TreeNode increasingBST(TreeNode root) {
    if(root==null){
        return null;
    }
    TreeNode dummyNode=new TreeNode(-1);
    cur=dummyNode;
    inorder(root);
    return dummyNode.right;
}

private void inorder(TreeNode root){
    if(root==null){
        return;
    }
    inorder(root.left);

    cur.right=root;
    cur=root;
    cur.left=null;

    inorder(root.right);
}

95

95 Unique Binary Search Trees II

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

//[start,end]的数据产生二叉树
private List<TreeNode> genenateTree(int start,int end){
    List<TreeNode> res=new ArrayList<>();
    if(start>end){
        res.add(null);
        return res;
    }

    for(int i=start;i<=end;i++){
        //i值作为根结点,构建该BST树
        List<TreeNode> left=genenateTree(start,i-1);
        List<TreeNode> right=genenateTree(i+1,end);
        for(TreeNode leftNode:left){
            for(TreeNode rightNode:right){
                TreeNode root=new TreeNode(i);
                root.left=leftNode;
                root.right=rightNode;
                res.add(root);
            }
        }
    }
    return res;
}

二叉树相关的所有操作

二分搜索树的基本操作