【力扣刷题】Day20——二叉树专题

文章目录

    • 23. 二叉搜索树的最小绝对差
    • 24. 二叉搜索树中的众数
    • 25. 二叉树的最近公共祖先
    • 26. 二叉搜索树的最近公共祖先
    • 27. 二叉搜索树中的插入操作
    • 28. 删除二叉搜索树中的节点


上一篇文章:【力扣刷题】Day19——二叉树专题_塔塔开!!!的博客-CSDN博客

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

题目链接:530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)

思路:这题根验证二叉搜索树得第二种写法如出一辙,这不过本题他就是一棵二叉搜索树,其中序遍历是有序的,我们利用这一性质,使用pre(相当于一个指针)记录当前节点的前一个节点,每次在根处进行判断即可。

Code

class Solution {
    int pre = -1;// 用作于指针
    int res = 0x3f3f3f3f;
    public int getMinimumDifference(TreeNode root) {
        dfs(root);
        return res;
    }
    public void dfs(TreeNode root){
        if(root == null){
            return ;
        }

        // 左
        dfs(root.left);
        if(pre == -1){
            pre = root.val;
        }else {
            res = Math.min(res, Math.abs(root.val - pre));
            pre = root.val;
        }
        // 右
        dfs(root.right);
    }
}

24. 二叉搜索树中的众数

题目链接:501. 二叉搜索树中的众数 - 力扣(LeetCode)

Code

思路一:哈希表计数(普通二叉树的求法)

自己写的还是太繁琐了,hhhhh…

/**
    可以用一个哈希表来计数, 找到出现次数最多的所有数
*/
class Solution {
    Map<Integer, Integer> mp = new HashMap<>();
    public int[] findMode(TreeNode root) {
        dfs(root);

        int max_cnt = 0;
        for (Integer key : mp.keySet()) {
            max_cnt = Math.max(max_cnt, mp.get(key));
        }
        
        List<Integer> list = new ArrayList<>();
        for(Integer key : mp.keySet()){
            if(mp.get(key) == max_cnt){
                list.add(key);
            }
        }

        int[] res = new int[list.size()];
        for(int i = 0; i < list.size(); i ++) res[i] = list.get(i);
        
        return res;
    }
    public void dfs(TreeNode root){
        if(root == null){
            return ;
        }
        dfs(root.left);
        mp.put(root.val, mp.getOrDefault(root.val, 0) + 1);
        dfs(root.right);
    }
}

思路二:二叉搜索数的性质进行求解(双指针比较当前节点和前驱节点,计数, 更新等)

class Solution {
    List<Integer> list = new ArrayList<>();
    int pre = -1;
    int cnt = 0;// 表示当前节点的值
    int max_cnt = 0;// 最大出现次数
    public int[] findMode(TreeNode root) {
        dfs(root);
        int[] res = new int[list.size()];
        for(int i = 0; i < list.size(); i ++) res[i] = list.get(i);
        return res;
    }
    public void dfs(TreeNode root){
        if(root == null){
            return ;
        }
        // 左
        dfs(root.left);

        // 根
        if(pre == root.val){
            cnt ++;
            pre = root.val;
        }else {// 新的节点
            cnt = 1;
            pre = root.val;
        }

        // 更新max_cnt
        if(cnt == max_cnt){
            // 如果cnt == max_cnt,就把当前节点加入到集合中
            list.add(root.val);
        }else if(cnt > max_cnt){
            //  (出现了更多的)
            // 否则,当前节点的值重复量是最多的,直接把list清空,然后
            // 把当前节点的值加入到集合中
            max_cnt = cnt;
            list.clear();
            list.add(root.val);
        }
        // 右
        dfs(root.right);
    }
}

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

题目链接:236. 二叉树的最近公共祖先 - 力扣(LeetCode)

思路:dfs后序遍历,从低往上搜索公共祖先

Code

/**
    由于是找找最近的,我们dfs的顺序采用 后序遍历(左右根,最后处理根),最终一定是最近的
    本题的关键就在于,判断当前节点的左右子树是否包含 p q:
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        return dfs(root, p, q);
    }
    // dfs函数:返回pq的最近公共祖先
    // 如果以root为根的子树(左右子树)包含p和q,则返回最近公共祖先
    // 如果...只包含 p,则返回q
    // 如果...只包含 q,则返回p
    // 如果都不包含,则返回NULL
    public TreeNode dfs(TreeNode root, TreeNode p, TreeNode q){
        if(root == null || root == p || root == q){
            return root;
        }
        // 判断左右子树是否包含 p q
        // 左右
        TreeNode left = dfs(root.left, p, q);
        TreeNode right = dfs(root.right, p, q);
        if(left == null) return right;// 左边不包含pq 那么最近..就在右边
        if(right == null) return left;

        // 左边和右边都不空(p q左右各一个 那么此时根节点就为最近公共祖先)	// 根
        return root;
    }
}

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

题目链接:235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)

Code

用上一题的二叉树的最近公共祖先的代码完全可以过(二叉搜索树也是二叉树嘛!!)

/**
    由于是找找最近的,我们dfs的顺序采用 后序遍历(左右根,最后处理根),最终一定是最近的
    本题的关键就在于,判断当前节点的左右子树是否包含 p q:
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        return dfs(root, p, q);
    }

    public TreeNode dfs(TreeNode root, TreeNode p, TreeNode q){
        if(root == null || root == p || root == q){
            return root;
        }

        TreeNode left = dfs(root.left, p, q);
        TreeNode right = dfs(root.right, p, q);
        if(left == null) return right;
        if(right == null) return left;
        return root;
    }
}

利用二叉搜索树的性质:左子树的值都比跟小,右子树的值都比根大,这样我们就可以确定搜索的方向了!

  • 如果当前根节点root的值 比 q p大,那么说明p q的最近公共节点在左子树,我们遍历左子树即可
  • 如果当前根节点root的值 比 q p小,那么说明p q的最近公共节点在右子树,我们遍历左子树即可
  • p q各位于当前root的左右子树,那么此时root即为最近公共祖先

跟上一题还是一样的思路,只不过我们明确了遍历的方向而已,关键依旧在于判断 左右子树是否包含p和q

Code

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        return dfs(root, p, q);
    }
    public TreeNode dfs(TreeNode root, TreeNode p, TreeNode q){
        if(root == null || root == p || root == q){
            return root;
        }

        if(root.val > p.val && root.val > q.val) return dfs(root.left, p, q);
        if(root.val < p.val && root.val < q.val) return dfs(root.right, p, q);

        return root;
    }
}

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

题目链接:701. 二叉搜索树中的插入操作 - 力扣(LeetCode)

思路:利用二叉搜索树的性质,遍历找到该插入位置(空节点)即可

  • 递归出口:当root为空我们创建要插入的节点node,然后return node,最后会不断的回溯返回,直到根节点,最终递归完整结束返回根节点即可

  • 当前root.val > val,说明要往左子树进行插入操作

  • 当前root.val < val,说明要往右子树进行插入操作

Code

class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        return dfs(root, val);
    }
    public TreeNode dfs(TreeNode root, int val){
        if(root == null){// 递归出口,之后不断回溯返回,最终形成一棵树
            TreeNode node = new TreeNode(val);
            return node;
        }
        if(root.val > val) root.left = dfs(root.left, val);
        if(root.val < val) root.right = dfs(root.right, val);

        return root;
    }
}

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

题目链接:450. 删除二叉搜索树中的节点 - 力扣(LeetCode)

根据二叉搜索树的性质

  • 如果目标节点大于当前节点值,则去右子树中删除;
  • 如果目标节点小于当前节点值,则去左子树中删除;
  • 如果目标节点就是当前节点,分为以下三种情况:
    • 其无左子:其右子顶替其位置,删除了该节点;
    • 其无右子:其左子顶替其位置,删除了该节点;
    • 其左右子节点都有:其左子树转移到其右子树的最左节点的左子树上,然后右子树顶替其位置,由此删除了该节点。

【力扣刷题】Day20——二叉树专题_第1张图片

Code

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        return dfs(root, key);
    }
    public TreeNode dfs(TreeNode root, int key){
        if(root == null){
            return null;
        }

        if(root.val > key) root.left = dfs(root.left, key);
        else if(root.val < key) root.right = dfs(root.right, key);
        else{// 当前节点是要删除的节点
            if(root.left == null) return root.right;// 情况1:左子树为空
            if(root.right == null) return root.left;// 情况2:右子树为空

            // 情况3:左右都不为空
            TreeNode node = root.right;
            while(node.left != null){// 找出右子树最左的节点
                node = node.left;
            }
            node.left = root.left;// 删除欲删除节点 拼接
            root = root.right;// 跟换删除后树的根节点
        }

        // 递归完整结束后 返回根节点
        return root;
    }
}


你可能感兴趣的:(代码随想录力扣刷题,leetcode,算法,职场和发展)