LeetCode树经典题目(一)

427. 建立四叉树

https://leetcode-cn.com/problems/construct-quad-tree/
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路:对于一个给定的nn的格子,先判断这nn个格子是否都是0或者都是1,如果是,直接返回一个节点,不需要创建子节点;否则。递归的创建4个子节点,即将当前的nn个格子分成4个n/2n/2的矩形,然后重复上述步骤
细节:为了知道n*n个格子是否都是0或者都是1,可以先建立一个前缀和数组,给定(a,b) (c,d) 这两个点(左上角和右下角)可以求出该矩形的元素和,判断和是否为0(元素全为0)或者等于面积(元素全为1);如果不是,则根据(a,b) (c,d) 找出分割出来的四个子矩形的左上角和右上角,进行递归操作

/*
// Definition for a QuadTree node.
class Node {
    public boolean val;
    public boolean isLeaf;
    public Node topLeft;
    public Node topRight;
    public Node bottomLeft;
    public Node bottomRight;

    
    public Node() {
        this.val = false;
        this.isLeaf = false;
        this.topLeft = null;
        this.topRight = null;
        this.bottomLeft = null;
        this.bottomRight = null;
    }
    
    public Node(boolean val, boolean isLeaf) {
        this.val = val;
        this.isLeaf = isLeaf;
        this.topLeft = null;
        this.topRight = null;
        this.bottomLeft = null;
        this.bottomRight = null;
    }
    
    public Node(boolean val, boolean isLeaf, Node topLeft, Node topRight, Node bottomLeft, Node bottomRight) {
        this.val = val;
        this.isLeaf = isLeaf;
        this.topLeft = topLeft;
        this.topRight = topRight;
        this.bottomLeft = bottomLeft;
        this.bottomRight = bottomRight;
    }
};
*/

class Solution {
    public Node construct(int[][] grid) {
        int m=grid.length,n=grid[0].length;
        int[][] pre=new int[m+1][n+1];
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                pre[i][j]=pre[i][j-1]+pre[i-1][j]+grid[i-1][j-1]-pre[i-1][j-1];
            }
        }
     

        return dfs(grid,pre,0,0,m-1,n-1);
    }
    public Node dfs(int[][] grid,int[][] pre,int a,int b,int c,int d){
        int sum=pre[c+1][d+1]-pre[a][d+1]-pre[c+1][b]+pre[a][b];
        int w=d-b+1,h=c-a+1;
        if(sum==0||sum==w*h)
            return new Node(grid[a][b]==1,true);//叶子节点 val值取决于grid[a][b]是0还是1
        Node root=new Node(true,false);//非叶子节点
        root.topLeft=dfs(grid,pre,a,b,a+h/2-1,b+w/2-1);//左上角的矩形
        root.topRight=dfs(grid,pre,a,b+w/2,a+h/2-1,d);
        root.bottomLeft=dfs(grid,pre,a+h/2,b,c,b+w/2-1);
        root.bottomRight=dfs(grid,pre,a+h/2,b+w/2,c,d);
        return root;
    }
}

在这里插入图片描述

面试题 04.06. 后继者

https://leetcode.cn/problems/successor-lcci/

在这里插入图片描述

思路:对于一个BST而言,节点X的后继分为两种情况:

  1. X的右子树不为空,则X的后继为右子树中的最小节点
  2. X的右子树为空,则X的后继为X的第一个左祖先节点Y(Y是X的祖先节点,并且X在Y的左子树中)
class Solution {
    public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
        if(p.right!=null){
            TreeNode node=p.right;
            while(node.left!=null)
                node=node.left;
            return node;
        }
        TreeNode successor=null;
        TreeNode node=root;
        while(node!=null){
            if(node.val>p.val){
                successor=node;//suc指向p的第一个右祖先节点
                node=node.left;
            }else{
                node=node.right;
            }
        }
        return successor;
    }
   
}
//O(n)
//O(1)

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

https://leetcode.cn/problems/sum-of-root-to-leaf-binary-numbers/
在这里插入图片描述

思路:从上往下累加数据,对于叶子节点,直接返回节点值;对于非叶子节点,返回其左子子树的数值累加和,sum=sum<<1|val : 表示将将val添加到二进制右边形成的数值

class Solution {
   
    public int sumRootToLeaf(TreeNode root) {
        return dfs(root,0);
    }
    public int dfs(TreeNode root,int sum){
        if(root==null)
            return 0;
        sum=sum<<1|root.val;
        if(root.left==null&&root.right==null){
            return sum;
        }
        return dfs(root.left,sum)+dfs(root.right,sum);
    }
}
//O(n)
//O(n)

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

https://leetcode.cn/problems/delete-node-in-a-bst/
在这里插入图片描述

思路:删除BST中的某个节点x,分为以下4种情况(假设待删除节点x存在于BST中):

  1. x是叶子节点
  2. x只有左子节点
  3. x只有右子节点
  4. x既有左子节点也有右子节点
class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if(root==null){
            return null;
        }
        if(root.val<key){//当前结点值小于key 去root的右子树中删除
            root.right=deleteNode(root.right,key);
        }else if(root.val>key){//当前结点值大于key 去root的左子树中删除
            root.left=deleteNode(root.left,key);
        }else if(root.val==key){//当前root节点是待删除节点
            if(root.left==null&root.right==null){//当前节点是叶子节点 直接删除
                return null;
            }else if(root.left==null){//当前节点没有左子节点 用右子节点替代root
               return root.right;
           }else if(root.right==null){//当前节点没有右子节点 用左子节点替代root
               return root.left;
           }else{//当前节点root存在左右子节点  用右子树中的最小节点替代root 
               TreeNode tmp=root;//tmp保存原来的root
               root=findMin(tmp.right);//用右子树中的最小节点替代root 
               root.right=deleteMin(tmp.right);//删除最小节点的子树作为右子树
               root.left=tmp.left;//原先root节点的左子树作为新root节点的左子树
           }

        }
        return root;
    }
    //查找以node节点为根的子树中的最小节点
    public TreeNode findMin(TreeNode node){
        if(node.left==null){
            return node;
        }
        return findMin(node.left);
        
    }
    //删除以node为根节点的子树中的最小节点
    public TreeNode deleteMin(TreeNode node){
        if(node.left==null){
            return node.right;
        }
        node.left=deleteMin(node.left);
        return node;
    }
}
//O(n)
//O(n)

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

https://leetcode.cn/problems/minimum-absolute-difference-in-bst/
在这里插入图片描述

思路:对BST进行中序遍历可以得到一个升序序列,最简单的做法是用一个list,中序遍历记录各个节点的值,再遍历一遍list求得相邻元素的最小差值;优化的做法是不使用list,而是在中序遍历的过程中使用一个pre变量记录前一个结点的值,然后不断更新当前节点和前一个节点的最小差值,更新差值之后,当前节点就成为pre

class Solution {
    int pre=-1;
    int min=Integer.MAX_VALUE;
    public int getMinimumDifference(TreeNode root) {
        dfs(root);
        return min;
    }
    public void dfs(TreeNode root){
        if(root==null){
            return;
        }
        if(root.left!=null){
            dfs(root.left);
        }
        if(pre==-1){
            pre=root.val;
        }else{
            min=Math.min(min,root.val-pre);
            pre=root.val;
        }
        if(root.right!=null){
            dfs(root.right);
        }
    }
}
//O(n)
//O(n)

99. 恢复二叉搜索树

https://leetcode.cn/problems/recover-binary-search-tree/
在这里插入图片描述

思路: 先对BST进行中序遍历,并使用一个list记录中序遍历的节点,然后找出两个需要交换的节点;以1 2 3 4 5 6->1 5 3 4 2 6为例,2和5发生了交换,如何找出这两个发生交换的元素?遍历交换后的数组,如果第一次找到nums[i]>nums[i+1], 那么nums[i]一定是二者之一(5),对于另外一个元素,则需要继续往后遍历,最后一个满足条件nums[i]>nums[i+1]nums[i+1]就是另外一个元素(2),找到这两个元素后,交换这两个节点的值即可

class Solution {
    List<TreeNode> list=new ArrayList<>();
    public void recoverTree(TreeNode root) {
        inorder(root);
        TreeNode x=null,y=null;
        for(int i=0;i<list.size()-1;i++){
            if(list.get(i).val>list.get(i+1).val){
                y=list.get(i+1);
                if(x==null){
                    x=list.get(i);
                }
            }
        }
        int tmpVal=x.val;
        x.val=y.val;
        y.val=tmpVal;
    }
    public void inorder(TreeNode root){
        if(root==null){
            return;
        }
        inorder(root.left);
        list.add(root);
        inorder(root.right);
    }
}
//O(n)
//O(n)

1008. 前序遍历构造二叉搜索树

https://leetcode.cn/problems/construct-binary-search-tree-from-preorder-traversal/
在这里插入图片描述

思路1:递归创建,每次当前子数组中的第一个元素是root节点,然后找到左右子树的分界,然后根据分界线来定位左右子树的范围

class Solution {
    public TreeNode bstFromPreorder(int[] preorder) {
        return bstFromPreorder(preorder,0,preorder.length-1);
    }
    public TreeNode  bstFromPreorder(int[] preorder,int start,int end){
        if(start>end){
            return null;
        }
        TreeNode root=new TreeNode(preorder[start]);
        start++;
        int tmp=start;
        while(start<=end){//查找左右子树的分界 循环结束后start执行root的右子节点
            if(preorder[start]>root.val){
                break;
            }
            start++;
        }
        root.left=bstFromPreorder(preorder,tmp,start-1);
        root.right=bstFromPreorder(preorder,start,end);
        return root;
    }
}
//O(n^2) 查找边界的累计次数为n^2
//O(n)

思路2:不必每次查找左右子树的分界,将上下界作为参数进行传递,处于上下界范围内的节点是上一层root的子节点,否则不是

class Solution {
    int len;
    int index;
    int[] preorder;
    public TreeNode bstFromPreorder(int[] preorder) {
        this.len=preorder.length;
        this.preorder=preorder;
        return bstFromPreorder(Integer.MIN_VALUE,Integer.MAX_VALUE);
    }
    public TreeNode  bstFromPreorder(int lowerBound,int upperBound){
        if(index==len){//所有元素已经被加入到BST中
            return null;
        }
        int cur=preorder[index];
        if(cur<lowerBound||cur>upperBound){//当前遍历到的元素不在[low,up]范围内 回溯 说明当前cur不是上一层
            return null;//递归中root的左子节点或右子节点
        }
        index++;//当前cur是上一层root的子节点
        TreeNode root=new TreeNode(cur);
        root.left=bstFromPreorder(lowerBound,cur);//root节点是左子树的上界
        root.right=bstFromPreorder(cur,upperBound);//root节点是右子树的下界
        return root;
    }
}
//O(n) 
//O(n)

199. 二叉树的右视图

https://leetcode.cn/problems/binary-tree-right-side-view/
在这里插入图片描述

思路1:BFS, 遍历时,先将下一层的右子节点加入队列,这样当遍历到下一层时,第一个节点就是当前层所能看到的节点

class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> ans=new ArrayList<>();
        if(root==null){
            return ans;
        }
        LinkedList<TreeNode> q=new LinkedList<>();
        q.offer(root);
        while(!q.isEmpty()){
            int sz=q.size();
            for(int i=0;i<sz;i++){
                TreeNode node=q.poll();
                if(i==0){//由于每层是先添加右子节点的 所以第一个就是当前层所能看到的节点
                    ans.add(node.val);
                }
                if(node.right!=null){//先添加右子节点
                    q.offer(node.right);
                }
                if(node.left!=null){
                    q.offer(node.left);
                }
            }
        }
        return ans;
    }
}
//O(n)
//O(n)

思路2:DFS, 按照根右左的顺序进行深度遍历,当前深度和集合中的元素的个数相同时,则将当前节点加入集合中

class Solution {
    List<Integer> ans=new ArrayList<>();
    public List<Integer> rightSideView(TreeNode root) {
        dfs(root,0);
        return ans;
    }
    public void dfs(TreeNode root,int depth){
        if(root==null){
            return;
        }
        if(ans.size()==depth){//因为每一层只会加入一个节点 因此当depth和ans大小一致时就加入
            ans.add(root.val);
        }
        dfs(root.right,depth+1);//先访问右子节点
        dfs(root.left,depth+1);

    }
        
}
//O(n)
//O(n)

513. 找树左下角的值

在这里插入图片描述

思路1: DFS,使用一个形参表示当前遍历到的层数,另外再使用一个变量表示更新的次数,只有每一层的左边的第一个节点会被更新,因此只有当更新次数和层数相同时才进行更新

class Solution {
    int ans;
    int d;
    public int findBottomLeftValue(TreeNode root) {
        dfs(root,0);
        return ans;
    }
    public void dfs(TreeNode root,int depth){
        if(root==null){
            return;
        }
        if(depth==d){//只取每一层的第一个值
            ans=root.val;
            d++;
        }
        dfs(root.left,depth+1);
        dfs(root.right,depth+1);
    }
}
//O(n)
//O(n)

思路2:BFS,层次遍历时每次只对该层的第一个节点进行更新

class Solution {
  
    public int findBottomLeftValue(TreeNode root) {
       int ans=0;
       LinkedList<TreeNode> q=new LinkedList<>();
       q.offer(root);
       while(!q.isEmpty()){
           int sz=q.size();
           for(int i=0;i<sz;i++){
               TreeNode node=q.poll();
               if(i==0){//只对每一层的第一个节点进行更新
                   ans=node.val;
               }
               if(node.left!=null){
                   q.offer(node.left);
               }
               if(node.right!=null){
                   q.offer(node.right);
               }
           }
       }
       return ans;
    }
    
}
//O(n)
//O(n)

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

https://leetcode.cn/problems/second-minimum-node-in-a-binary-tree/
在这里插入图片描述

思路:根节点是整个树中最小的节点,DFS时如果发现当前节点node的值大于等于ans说明以node为根节点的子树中的所有值都大于等于ans, 此时直接返回; 如果没有返回,并且有当前节点node.val>minVal, 则更新第2小的值ans

class Solution {
    int ans=-1;//第2小的值
    int rootVal;
    public int findSecondMinimumValue(TreeNode root) {
        rootVal=root.val;//rootVal是最小的
        dfs(root);
        return ans;
    }
    public void dfs(TreeNode root){
        if(root==null){
            return;
        }
        if(ans!=-1&&root.val>=ans){//第2小的值已经更新过并且当前节点值>=ans 说明以当前节点为根的子树中的节点值都大于等于ans 直接返回
            return;
        }
        if(root.val>rootVal){//当前节点值比最小值大 当前值可能的第2小的值
            ans=root.val;
        }
        dfs(root.left);
        dfs(root.right);
    }
}
//O(n)
//O(n)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: leetcode高频100题java是指LeetCode网站上的100道经典算法题目,使用Java语言进行解答。这些题目涵盖了各种算法和数据结构,包括数组、链表、、图、排序、查找、动态规划等等。这些题目是程序员面试和算法学习的重要参考资料,也是提高编程能力和解决实际问题的有效途径。 ### 回答2: LeetCode是一个著名的程序员面试题库,其高频100题是指在面试中经常被问到的100道题目。这些题目涵盖了算法、数据结构、数学等各个领域,是程序员求职和成长过程中不可或缺的练习材料。本文将介绍这100题的Java解法。 这100题覆盖了许多经典算法,如动态规划、贪心算法、双指针等。对于Java程序员来说,最重要的是要掌握这些算法的核心思想及其实现方法。此外,Java核心类库中的一些常用类和函数,如String、Math、Arrays等也是解题过程中常用的工具。 对于高频100题,需要掌握的核心算法包括二分查找、数组和链表的操作、栈和队列、哈希表、递归等。此外,还需要掌握字符串操作、动态规划、贪心算法、回溯算法、深度/广度优先搜索等经典算法。 以数组和链表为例,需要掌握的操作包括数组的查找、排序和去重,以及链表的遍历、反转和合并等。使用Java语言来实现这些操作时,可以使用Java核心库中的Arrays和Collections类,它们提供了便捷的方法来处理数组和集合。 另外,Java语言还提供了众多数据结构,如栈、队列、双端队列、优先队列、堆等。这些数据结构可以进行复杂的算法操作,如优先队列可以实现贪心算法、堆可以实现堆排序等。Java还提供了Map和Set这两个关键字来实现哈希表的操作,使得开发人员可以轻松地实现哈希表。 最后,Java还提供了众多的工具类和常用函数,例如字符串操作函数、正则表达式、数学函数等。使用这些函数可以为算法提供更加便捷和高效的实现方法。 总之,掌握LeetCode高频100题的Java解法需要深入理解算法核心思想,灵活使用Java语言的各种工具和函数。在实际练习中,需要注重代码的可读性、复杂度和鲁棒性。 ### 回答3: LeetCode是全球最大的在线练习平台之一,通过解决LeetCode的问题,可以帮助人们提高他们的编程能力。在LeetCode上,有许多高频题,这些题目被认为是最重要的,因为这些题目经常在面试中出现。Java作为一种流行的编程语言,被大多数程序员所熟悉和使用。因此,LeetCode高频100题java是程序员们需要掌握的重要知识点。接下来,我将详细介绍LeetCode高频100题Java。 LeetCode高频100题java包括许多经典算法和数据结构问题,例如:动态规划、回溯、DFS、BFS、二分查找、排序、链表、栈、队列、、图等。每个问题都有一份完整的Java代码实现,以帮助程序员理解算法思路。不仅如此,Java代码还包括了详细的注释和解释,以帮助程序员更好地掌握算法LeetCode高频100题java对于Java程序员来说很重要,因为这些题目是在日常编码工作和面试中经常出现的问题。通过解决这些问题,程序员们能够提高他们的编码能力和思维能力。此外,这些问题也能帮助程序员们更好地了解Java语言的使用和优化,加深对Java语言特性的理解。 总结来说,对于Java程序员来说,掌握LeetCode高频100题java非常重要。这将帮助他们提高他们的编程水平,了解更多的算法和数据结构。通过解决这些问题,他们将更容易通过面试,获得更好的编程工作。因此,Java程序员们应该花费足够的时间和精力去学习和掌握LeetCode高频100题java。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

CodePanda@GPF

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

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

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

打赏作者

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

抵扣说明:

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

余额充值