• 1569. 将子数组重新排序得到同一个二叉查找树的方案数 数学+DFS


    1569. 将子数组重新排序得到同一个二叉查找树的方案数

    给你一个数组 nums 表示 1 到 n 的一个排列。我们按照元素在 nums 中的顺序依次插入一个初始为空的二叉查找树(BST)。请你统计将 nums 重新排序后,统计满足如下条件的方案数:重排后得到的二叉查找树与 nums 原本数字顺序得到的二叉查找树相同。

    比方说,给你 nums = [2,1,3],我们得到一棵 2 为根,1 为左孩子,3 为右孩子的树。数组 [2,3,1] 也能得到相同的 BST,但 [3,2,1] 会得到一棵不同的 BST 。

    请你返回重排 nums 后,与原数组 nums 得到相同二叉查找树的方案数。

    由于答案可能会很大,请将结果对 10^9 + 7 取余数。

    示例 1:

    输入:nums = [2,1,3]
    输出:1
    解释:我们将 nums 重排, [2,3,1] 能得到相同的 BST 。没有其他得到相同 BST 的方案了。
    

    示例 2:

    输入:nums = [3,4,5,1,2]
    输出:5
    解释:下面 5 个数组会得到相同的 BST:
    [3,1,2,4,5]
    [3,1,4,2,5]
    [3,1,4,5,2]
    [3,4,1,2,5]
    [3,4,1,5,2]
    

    示例 3:

    输入:nums = [1,2,3]
    输出:0
    解释:没有别的排列顺序能得到相同的 BST 。
    

    示例 4:

    输入:nums = [3,1,2,5,4,6]
    输出:19
    

    示例  5:

    输入:nums = [9,4,2,1,3,6,5,7,8,14,11,10,12,13,16,15,17,18]
    输出:216212978
    解释:得到相同 BST 的方案数是 3216212999。将它对 10^9 + 7 取余后得到 216212978。
    

    提示:

    • 1 <= nums.length <= 1000
    • 1 <= nums[i] <= nums.length
    • nums 中所有数 互不相同 。

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

    做题结果

     大概算是成功吧,已经吧组合公式+合成方式推导出来了,然后心想着,不可能这么难吧?看了题目确实用组合,然后没看答案推出来。

    方法:数学+DFS

    首先对于左边右边各有几个元素的情况,放置方式种类数,需要考虑。

    1. 假设左右子树都是链,那么必然是从上到下排的。那有几种呢?假设大写是左子树,小写是右子树,字母顺序代表大小的话,可能是这样排:AabBcC,也就是是说,同一边的顺序是一致的。这种情况,我们可以忽略数值的影响,看成XyyXyX,本质上,是把3个X放入长度为6,共有几种方法的组合数

    2. 然后我们可以考虑复杂一些的情况,也就是左边是链,假设长度是3,右边是 a为根,bc为左右子树,又怎么排呢?放置ABC的方式不变,依然可以看做XyyXyX,6选3的组合数。不同的是,y产生了一定的顺序。bc的顺序可以变化了。可以是abc或者acb,也就是两种情况,右侧排序数量2,合起来就是C(6,3)*2,组合数乘以右边获得的总路径数即为答案

    3. 如果两边都是完整的树呢?那左侧X的排序,也可以不止一种了,根据左侧路径即可

    4. 综上,对于当前节点,path=C(lenLeft+lenRight,leftLeft)*pathLeft*pathRight

    5. 所以当前节点路径数目,由子节点的节点数目+路径数目合成,当前节点作为根节点的总节点数目为 lenLeft+lenRight+1,也就成功通过子问题合成当前问题,实现了DFS

    6. 结束条件:空节点的路径为1,节点数0,叶子节点路径1,节点1

    1. class Solution {
    2. static final int CSIZE = 2000;
    3. static final int MOD = (int) (1e9+7);
    4. static long[][] C = new long[CSIZE+1][CSIZE+1];
    5. static{
    6. C[0][0] = 1;
    7. for(int i = 1; i < CSIZE+1; i++){
    8. C[i][0] =1;
    9. for(int j = 1; j <= i; j++){
    10. C[i][j] = (C[i-1][j]+C[i-1][j-1])%MOD;
    11. }
    12. }
    13. }
    14. public int numOfWays(int[] nums) {
    15. Node head = new Node(nums[0]);
    16. int n = nums.length;
    17. for(int i = 1; i < n; i++){
    18. insert(head,nums[i]);
    19. }
    20. int ans = (int) ((dfs(head)[0]+MOD-1)%MOD);
    21. return ans;
    22. }
    23. private void insert(Node head, int val){
    24. if(val
    25. if(head.left == null) head.left=new Node(val);
    26. else insert(head.left,val);
    27. }else{
    28. if(head.right==null) head.right = new Node(val);
    29. else insert(head.right,val);
    30. }
    31. }
    32. //path/cnt
    33. private long[] dfs(Node root){
    34. if(root == null) return new long[]{1,0};
    35. if(root.left == null && root.right == null) return new long[]{1,1};
    36. long[] a = dfs(root.left);
    37. long[] b = dfs(root.right);
    38. long path = C[(int)(a[1]+b[1])][(int)a[1]]*a[0]%MOD*b[0]%MOD;
    39. return new long[]{path,a[1]+b[1]+1};
    40. }
    41. class Node{
    42. Node left;
    43. Node right;
    44. int val;
    45. public Node(int val){
    46. this.val = val;
    47. }
    48. }
    49. }

  • 相关阅读:
    模块化软件架构:使用单体、微服务和模块化单体的优缺点
    php 支付宝支付(带回调)
    【图像处理-计算机视觉学习路线】个人记录
    Qlik Sense On-demand apps
    JS中原型相关的十个知识点总结
    论文解读(LG2AR)《Learning Graph Augmentations to Learn Graph Representations》
    解决:ImportError: cannot import name ‘get_config‘
    太神了!开源大佬的SpringBoot+微服务架构笔记,一般人真肝不出来
    【Java】继承——子类与父类有同名属性的情况。
    golang中for循环的使用详解
  • 原文地址:https://blog.csdn.net/yu_duan_hun/article/details/126474110