4.leetcode-二叉树

1.二叉树的最大深度

题目要求:

 难度:🌟

解答:

  • 递归+DFS
  • 树的总深度 = max(左子树深度,右子树深度) + 当前节点所在的一层深度

class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null){
            return 0;
        }
        int leftHeight=maxDepth(root.left);
        int rightHeight=maxDepth(root.right);

        return Math.max(leftHeight,rightHeight)+1;
    }
}

2.翻转二叉树

题目要求:

难度:🌟

解答:

  • 反转=把二叉树上的每一个节点的左右子节点进行交换
  • 递归的交换当前节点的左节点,递归的交换当前节点的右节点
  • 再交换当前节点的左右节点

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

        TreeNode left=invertTree(root.left);
        TreeNode right=invertTree(root.right);

        root.left=right;
        root.right=left;

        return root;
    }
}

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

题目要求:

难度:🌟🌟

解答:

  • BFS
  • 在遍历每一行的时候,只要把他们串联起来就OK


class Solution {
    public Node connect(Node root) {
        if(root == null){
            return root;
        }

        Queue<Node> queue = new LinkedList<>();
        queue.add(root);

        while(!queue.isEmpty()){
            int curLrvelNum = queue.size();//记录每层的节点数 循环时更新
            Node pre=null;
            for(int i=0;i<curLrvelNum;i++){
                Node curNode = queue.poll();
                //如果pre为空就表示node节点是这一行的第一个,
                //没有前一个节点指向他,否则就让前一个节点指向他
                if (pre != null) {
                    pre.next = curNode;
                }
                //然后再让当前节点成为下次循环的前一个节点
                pre=curNode;
                //子节点入队
                if (curNode.left != null){
                    queue.add(curNode.left);
                }   
                if (curNode.right != null){
                    queue.add(curNode.right);
                }
            }
        }
        return root;
    }
}
  • 纵向递归DFS
  • 每个 node 左子树的 next , 就是 node 的右子树

  • 每个 node 右子树的 next, 就是 node next 的 左子树

    public Node connect(Node root) {
        dfs(root, null);
        return root;
    }

    private void dfs(Node curr, Node next) {
        if (curr == null)
            return;
        curr.next = next;
        dfs(curr.left, curr.right);
        dfs(curr.right, curr.next == null ? null : curr.next.left);
    }


4.二叉树展开为链表

题目要求:

难度:🌟🌟

解答:

  • 递归 将左右子树处理
  • 将 x 的右子树接到左子树下方,然后将整个左子树作为右子树

class Solution {
    public void flatten(TreeNode root) {
        if(root == null){
            return ;
        }

        flatten(root.left);
        flatten(root.right);

        TreeNode left=root.left;
        TreeNode right=root.right;

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

        //最后拼接
        TreeNode P=root;
        while(P.right != null){
            P=P.right;
        }
        P.right=right;
    }
}

5.最大二叉树

题目要求:

难度:🌟🌟

解答:

  • 递归
  • 当前 nums 中的最大值就是根节点,然后根据索引递归调用左右数组构造左右子树即可

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

    public TreeNode build(int[] nums,int left,int right) {
        if(left>right){
            return null;
        }

        int index=-1;
        int maxVal=Integer.MIN_VALUE;
        //找到最大值
        for(int i=left;i<=right;i++){
            if(maxVal<nums[i]){
                maxVal=nums[i];
                index=i;
            }
        }
        
        //构造
        TreeNode root=new TreeNode(maxVal);
        root.left=build(nums,left,index-1);
        root.right=build(nums,index+1,right);

        return root;
    }
}

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

 题目要求:

难度:🌟🌟

解答:

  • 递归,利用前序遍历在中序遍历中划分左右子树
  • 用一个 HashMap 存储元素到索引的映射
class Solution {
    //key:元素值。  val:元素在中序遍历中的下标
    HashMap<Integer, Integer> valToIndex = new HashMap<>();

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        for(int i=0;i<inorder.length;i++){
            valToIndex.put(inorder[i],i);
        }
        return buildTree(preorder,0,preorder.length-1,
                         inorder,0,inorder.length-1);
    }

    public TreeNode buildTree(int[] preorder,int preStart,int preEnd,
                              int[] inorder,int inStart,int inEnd) {
        if(preStart > preEnd){
            return null;
        }
        //取出当前根结点                       
        int currRootVal=preorder[preStart];
        int currIndex=valToIndex.get(currRootVal);
        TreeNode currNode=new TreeNode(currRootVal);

        int leftSize=currIndex - inStart;//左子树 节点个数

        currNode.left=buildTree(preorder,preStart + 1,preStart+leftSize,
                                inorder,inStart,currIndex - 1);

        currNode.right=buildTree(preorder,preStart + leftSize + 1,preEnd,
                                 inorder,currIndex+1,inEnd);
        return currNode;
    }
}

7.寻找重复的子树

题目要求:

难度:🌟🌟

解答:

  • DFS+StringBuilder去拼接子树+HashMap记录出现次数
  • 使用 "_" 分割不同的节点值,同时对空节点进行保留(定义为空串 " "
class Solution {
    HashMap<String, Integer> recordMap = new HashMap<>();
    List<TreeNode> answer=new ArrayList<>();
    public List<TreeNode> findDuplicateSubtrees(TreeNode root) {
        DFS(root);
        return answer;
    }

    public String DFS(TreeNode root){
        if(root == null){
            return " ";
        }
        StringBuilder currTree = new StringBuilder();
        currTree.append(root.val).append("_");
        currTree.append(DFS(root.left)).append(DFS(root.right));
        
        String key=currTree.toString();
        recordMap.put(key, recordMap.getOrDefault(key, 0) + 1);
        if(recordMap.get(key) == 2){
            answer.add(root);
        }

        return key;
    }
}

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

题目要求:

 难度:🌟🌟

解答:

  • BST 的中序遍历其实就是升序排序的结果
class Solution {
    int res=0;
    int rank=0;
    public int kthSmallest(TreeNode root, int k) {
        // 利用 BST 的中序遍历特性
        traverse(root, k);
        return res;
    }

    public void traverse(TreeNode root, int k){
        if(root == null){
            return;
        }

        traverse(root.left, k);
        //中序遍历内容
        rank++;
        if(k == rank){
            res=root.val;
            return;
        }
        traverse(root.right,k);

    }
}

9.从二叉搜索树到更大和树

题目要求:

难度:🌟🌟

解答:

  • 利用 BST 的中序遍历特性,把递归顺序改一下(右 中 左),降序打印 BST
  • 维护一个外部累加变量 sum,然后把 sum 赋值给 BST 中的每一个节点
  • PS:那么每个节点都去计算右子树的和,不就行了吗?这是不行的。对于一个节点来说,确实右子树都是比它大的元素,但问题是它的父节点也可能是比它大的元素呀?这个没法确定的,我们又没有触达父节点的指针,所以二叉树的通用思路在这里用不了。

class Solution {
    public TreeNode bstToGst(TreeNode root) {
        traverse(root);
        return root;
    }

    int sum = 0;
    public void traverse(TreeNode root){
        if(root == null){
            return;
        }

        traverse(root.right);
        sum = sum + root.val;
        root.val=sum;
        traverse(root.left);

    }
}

10. 验证二叉搜索树

题目要求:

 难度:🌟🌟

解答:

  • 将值的上下限传入递归,进行比较。

if (root.left != null && root.left.val >= root.val) return false;

 if (root.right != null && root.right.val <= root.val) return false;

  • 代码仅仅检查了它的左右孩子节点是否符合左小右大的原则;不能全面检查左右子树的情况
class Solution {
    public boolean isValidBST(TreeNode root) {
        return isValidBST(root,null,null);
    }

    public boolean isValidBST(TreeNode root, TreeNode min, TreeNode max){

        if(root == null) return true;
        if(min != null&&root.val <= min.val) return false;
        if(max != null&&root.val >=max.val) return false;

        return isValidBST(root.left,null,root) && isValidBST(root.right,root,null);
    }
}

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

题目要求: 

难度:🌟🌟

解答:

  • 先找到该节点 ,再删除
  • 情况 1A 恰好是末端节点,两个子节点都为空,直接删除。
  • 情况 2A 只有一个非空子节点,那么它要让这个孩子接替自己的位置。
  • 情况 3A 有两个子节点,A 必须找到左子树中最大的那个节点,或者右子树中最小的那个节点来接替自己。
  • 以找到右子树中最小为例:
    • 先找到最小的那个节点,用指针指向他
    • 在右子树中删除它
    • 将当前跟节点替换成最小节点
class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if(root == null) return null;
        if(root.val == key){
            if(root.left == null) return root.right;
            if(root.right == null) return root.left;
            // 获得右子树最小的节点
            TreeNode minNodeInRight=getMin(root.right);
            // 删除右子树最小的节点
            root.right = deleteNode(root.right, minNodeInRight.val); 
            // 用右子树最小的节点替换 root 节点
            minNodeInRight.left = root.left;
            minNodeInRight.right = root.right;
            root = minNodeInRight;
        }else if(root.val > key){
            root.left=deleteNode(root.left,key);
        }else if(root.val < key){
            root.right=deleteNode(root.right,key);
        }

        return root;
    }

    public TreeNode getMin(TreeNode node) {
        // BST 最左边的就是最小的
        while (node.left != null) node = node.left;
        return node;
    }
}

12.不同的二叉搜索树

题目要求:

难度:🌟🌟

解答:

 

class Solution {
    public int numTrees(int n) {
        int dp[]=new int[n+1];
        dp[0]=1;
        dp[1]=1;
        for(int i =2;i<n+1;i++){
            for(int k=1;k<i+1;k++){
                dp[i]+=dp[k-1]*dp[i-k];
            }
        }
        return dp[n];
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值