• 1932. 合并多棵二叉搜索树 并查集+DFS


    1932. 合并多棵二叉搜索树

    给你 n 个 二叉搜索树的根节点 ,存储在数组 trees 中(下标从 0 开始),对应 n 棵不同的二叉搜索树。trees 中的每棵二叉搜索树 最多有 3 个节点 ,且不存在值相同的两个根节点。在一步操作中,将会完成下述步骤:

    • 选择两个 不同的 下标 i 和 j ,要求满足在 trees[i] 中的某个 叶节点 的值等于 trees[j] 的 根节点的值 。
    • 用 trees[j] 替换 trees[i] 中的那个叶节点。
    • 从 trees 中移除 trees[j] 。

    如果在执行 n - 1 次操作后,能形成一棵有效的二叉搜索树,则返回结果二叉树的 根节点 ;如果无法构造一棵有效的二叉搜索树返回 null 。

    二叉搜索树是一种二叉树,且树中每个节点均满足下述属性:

    • 任意节点的左子树中的值都 严格小于 此节点的值。
    • 任意节点的右子树中的值都 严格大于 此节点的值。

    叶节点是不含子节点的节点。

    示例 1:

    输入:trees = [[2,1],[3,2,5],[5,4]]
    输出:[3,2,5,1,null,4]
    解释:
    第一步操作中,选出 i=1 和 j=0 ,并将 trees[0] 合并到 trees[1] 中。
    

    删除 trees[0] ,trees = [[3,2,5,1],[5,4]] 。
    
    在第二步操作中,选出 i=0 和 j=1 ,将 trees[1] 合并到 trees[0] 中。
    删除 trees[1] ,trees = [[3,2,5,1,null,4]] 。
    
    

    结果树如上图所示,为一棵有效的二叉搜索树,所以返回该树的根节点。

    示例 2:

    输入:trees = [[5,3,8],[3,2,6]]
    输出:[]
    解释:
    选出 i=0 和 j=1 ,然后将 trees[1] 合并到 trees[0] 中。
    删除 trees[1] ,trees = [[5,3,8,2,6]] 。
    
    

    结果树如上图所示。仅能执行一次有效的操作,但结果树不是一棵有效的二叉搜索树,所以返回 null 。
    

    示例 3:

    输入:trees = [[5,4],[3]]
    输出:[]
    解释:无法执行任何操作。
    

    提示:

    • n == trees.length
    • 1 <= n <= 5 * 1e4
    • 每棵树中节点数目在范围 [1, 3] 内。
    • 输入数据的每个节点可能有子节点但不存在子节点的子节点
    • trees 中不存在两棵树根节点值相同的情况。
    • 输入中的所有树都是 有效的二叉树搜索树 。
    • 1 <= TreeNode.val <= 5 * 1e4.

    来源:力扣(LeetCode)
    链接:https://leetcode.cn/problems/merge-bsts-to-create-single-bst
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    做题结果

    成功,这题前后写了两百行,但是写出来了

    方法:并查集

    1.按根分类,同根的检查,同根有叶子则合并,两个同值的BST根,如果都不是叶子则无解

    2. 枚举根节点,找到它的叶子合并

    3. 特别地,可能存在一定的循环,比如 [1,2],[2,null,1],这种情况用并查集判别分组,防止重复合并

    4.合并完,也不一定是合法的二叉搜索树,比如[1,2]和[2,null,1] 合并后必然存在重复,所以按照BST定义检查一遍

    1. class Solution {
    2. Map parent = new HashMap<>();
    3. Map sizes = new HashMap<>();
    4. public TreeNode canMerge(List trees) {
    5. //1.改成哈希映射,根->树,同时检查是否有多个同值节点
    6. Map rootTree = new HashMap<>();
    7. for(TreeNode tree:trees){
    8. if(!rootTree.containsKey(tree.val)) rootTree.put(tree.val,tree);
    9. else{
    10. if(isLeaf(rootTree.get(tree.val))) rootTree.put(tree.val,tree);
    11. else if(!isLeaf(tree)) return null;
    12. }
    13. }
    14. for(Integer key:rootTree.keySet()){
    15. parent.put(key,key);
    16. sizes.put(key,1);
    17. }
    18. Set visited = new HashSet<>();
    19. //2. 检查树的连通性,能合并的合并
    20. for(TreeNode t:rootTree.values()){
    21. if(isLeaf(t)) continue;
    22. List leafs = new ArrayList<>();
    23. fillLeafs(t,leafs);
    24. for(Integer leaf:leafs){
    25. if(!visited.contains(leaf) && rootTree.containsKey(leaf)){
    26. if(isConnect(t.val,leaf)) continue;
    27. visited.add(leaf);
    28. t = combine(t,rootTree.get(leaf));
    29. connect(t.val,leaf);
    30. }
    31. }
    32. }
    33. //移除完所有树,剩下一个有效的
    34. for(Integer visit:visited) rootTree.remove(visit);
    35. //没合并完,肯定不行
    36. if(rootTree.size()!=1) return null;
    37. TreeNode t = null;
    38. for(TreeNode tmp:rootTree.values()) t = tmp;
    39. return passCheck(t)?t:null;
    40. }
    41. private void connect(int a, int b){
    42. int rootA = getRoot(a);
    43. int rootB = getRoot(b);
    44. if(rootA == rootB) return;
    45. if(sizes.get(rootA)>sizes.get(rootB)){
    46. parent.put(rootB,rootA);
    47. sizes.put(rootA,sizes.get(rootA)+sizes.get(rootB));
    48. }else{
    49. parent.put(rootA,rootB);
    50. sizes.put(rootB,sizes.get(rootA)+sizes.get(rootB));
    51. }
    52. }
    53. private boolean isConnect(int a,int b){
    54. return getRoot(a)==getRoot(b);
    55. }
    56. private int getRoot(int a){
    57. while(a!=parent.get(a)){
    58. parent.put(a,parent.get(parent.get(a)));
    59. a=parent.get(a);
    60. }
    61. return a;
    62. }
    63. TreeNode pre = null;
    64. private boolean passCheck(TreeNode root){
    65. if(root ==null) return true;
    66. if(!passCheck(root.left)) return false;
    67. if(pre!=null&&root.val<=pre.val) return false;
    68. pre = root;
    69. return passCheck(root.right);
    70. }
    71. private TreeNode combine(TreeNode p, TreeNode child){
    72. if(p==null) return null;
    73. if(isLeaf(p) && p.val==child.val) return child;
    74. p.left = combine(p.left,child);
    75. p.right = combine(p.right,child);
    76. return p;
    77. }
    78. void fillLeafs(TreeNode t,List leafs){
    79. if(t==null) return;
    80. if(isLeaf(t)){
    81. leafs.add(t.val);
    82. return;
    83. }
    84. fillLeafs(t.left,leafs);
    85. fillLeafs(t.right,leafs);
    86. }
    87. private boolean isLeaf(TreeNode treeNode){
    88. if(treeNode == null) return false;
    89. return treeNode.left == null && treeNode.right == null;
    90. }
    91. }
  • 相关阅读:
    MySQL之视图、存储过程
    Flink DataStream 作业调优
    Python-爬虫(Scrapy爬虫框架,爬取豆瓣读书和评分)
    二.RocketMQ基础概念及名词说明
    猿创征文|Python快速刷题网站——牛客网 数据分析篇(十三)
    ubuntu22.4配置nginx和php
    【Java牛客刷题】入门篇(02)
    Java开发学习(三十三)----Maven私服(一)私服简介安装与私服分类
    三、类和对象
    quickapp_快应用_tabBar
  • 原文地址:https://blog.csdn.net/yu_duan_hun/article/details/126550601