当前位置 : 主页 > 编程语言 > java >

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

来源:互联网 收集:自由互联 发布时间:2022-09-02
1569. 将子数组重新排序得到同一个二叉查找树的方案数 给你一个数组​​nums​​​表示​​1​​​到​​n​​​的一个排列。我们按照元素在​​nums​​​中的顺序依次插入一个初


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:

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

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

示例 2:

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

输入: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:

1569. 将子数组重新排序得到同一个二叉查找树的方案数 数学+DFS_深度优先_03

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

示例 4:

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

输入: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

class Solution {
static final int CSIZE = 2000;
static final int MOD = (int) (1e9+7);
static long[][] C = new long[CSIZE+1][CSIZE+1];
static{
C[0][0] = 1;
for(int i = 1; i < CSIZE+1; i++){
C[i][0] =1;
for(int j = 1; j <= i; j++){
C[i][j] = (C[i-1][j]+C[i-1][j-1])%MOD;
}
}
}
public int numOfWays(int[] nums) {
Node head = new Node(nums[0]);
int n = nums.length;
for(int i = 1; i < n; i++){
insert(head,nums[i]);
}

int ans = (int) ((dfs(head)[0]+MOD-1)%MOD);
return ans;
}

private void insert(Node head, int val){
if(val<head.val){
if(head.left == null) head.left=new Node(val);
else insert(head.left,val);
}else{
if(head.right==null) head.right = new Node(val);
else insert(head.right,val);
}
}

//path/cnt
private long[] dfs(Node root){
if(root == null) return new long[]{1,0};

if(root.left == null && root.right == null) return new long[]{1,1};

long[] a = dfs(root.left);
long[] b = dfs(root.right);

long path = C[(int)(a[1]+b[1])][(int)a[1]]*a[0]%MOD*b[0]%MOD;
return new long[]{path,a[1]+b[1]+1};
}

class Node{
Node left;
Node right;
int val;
public Node(int val){
this.val = val;
}
}
}
上一篇:Java线程池创建方式和应用场景
下一篇:没有了
网友评论