给定一个整数数组arr = [5, 6, 1]
。当我们用这个输入以相同的顺序构造一个 BST 时,我们将“5”作为根,“6”作为右孩子,“1”作为左孩子。
现在,如果我们的输入更改为 [5,1,6],我们的 BST 结构仍然是相同的。
那么给定一个整数数组,如何找到输入数组的不同排列的数量,从而产生与原始数组顺序上形成的 BST 相同的 BST?
给定一个整数数组arr = [5, 6, 1]
。当我们用这个输入以相同的顺序构造一个 BST 时,我们将“5”作为根,“6”作为右孩子,“1”作为左孩子。
现在,如果我们的输入更改为 [5,1,6],我们的 BST 结构仍然是相同的。
那么给定一个整数数组,如何找到输入数组的不同排列的数量,从而产生与原始数组顺序上形成的 BST 相同的 BST?
您的问题相当于计算给定 BST 的拓扑排序数的问题。
例如,对于 BST
10
/ \
5 20
\7 | \
15 30
可以像这样手动计算拓扑排序集:每个排序有 10 个开始。从 20 开始的子树的拓扑排序数为两个:(20, 15, 30) 和 (20, 30, 15)。以 5 开头的子树只有一个顺序:(5, 7)。这两个序列可以以任意方式交织,导致 2 x 10 次交织,从而产生 20 个产生相同 BST 的输入。下面列举了前 10 个案例 (20, 15, 30):
10 5 7 20 15 30
10 5 20 7 15 30
10 5 20 15 7 30
10 5 20 15 30 7
10 20 5 7 15 30
10 20 5 15 7 30
10 20 5 15 30 7
10 20 15 5 7 30
10 20 15 5 30 7
10 20 15 30 5 7
情况 (20, 30, 15) 是类似的——您可以检查以下任何一个输入是否产生相同的 BST。
这个例子还提供了一个递归规则来计算排序的数量。对于叶子,数量为 1。对于具有一个子节点的非叶子节点,该数量等于子节点的拓扑排序数。对于具有两个子树大小为 |L| 的子节点的非叶节点 和 |R|,分别具有 l 和 r 排序,数量等于
l x r x INT(|L|, |R|)
其中 INT 是 |L| 的可能交错数 和 |R| 元素。这可以通过 (|L| + |R|) 轻松计算!/ (|L|!x |R|!)。对于上面的示例,我们得到以下递归计算:
Ord(15) = 1
Ord(30) = 1
Ord(20) = 1 x 1 x INT(1, 1) = 2 ; INT(1, 1) = 2! / 1 = 2
Ord(7) = 1
Ord(5) = 1
Ord(10) = 1 x 2 x INT(2, 3) = 2 x 5! / (2! x 3!) = 2 x 120 / 12 = 2 x 10 = 20
这解决了问题。
注意:此解决方案假设 BST 中的所有节点都有不同的密钥。
感谢antti.huima的解释!这有助于我理解。这是一些C++:
#include <vector>
#include <iostream>
using namespace std;
int factorial(int x) {
return (x <= 1) ? 1 : x * factorial(x - 1);
}
int f(int a, int b) {
return factorial(a + b) / (factorial(a) * factorial(b));
}
template <typename T>
int n(vector<T>& P) {
if (P.size() <= 1) return 1;
vector<T> L, R;
for (int i = 1; i < P.size(); i++) {
if (P[i] < P[0])
L.push_back(P[i]);
else
R.push_back(P[i]);
}
return n(L) * n(R) * f(L.size(), R.size());
}
int main(int argc, char *argv[]) {
vector<int> a = { 10, 5, 7, 20, 15, 30 };
cout << n(a) << endl;
return 0;
}
如果您对递归、排列和组合知之甚少,并且熟悉二叉搜索树(显然),这个问题可以很容易地解决。
首先,您使用给定的序列构建二叉搜索树。您也可以在数组中执行相同的操作,但树形可视化会描绘出一幅好的画面。
对于给定的序列 arr[1..n],第一个元素将保持原样在给定数组中,并且只需要在 arr[2..n] 中引入排列。
认为:
bag1 = arr[2..n] 中小于 arr[0] 的元素数。
和,
bag2 = arr[2..n] 中大于 arr[0] 的元素数。
由于序列中 bag1 中元素的排列不会与 bag2 中存在的数字在形成二叉搜索树时产生冲突,因此可以通过从 (n-1) 个元素中挑选 bag1 元素来开始计算答案permutate and then rest ((n-1) - bag1) = bag2 元素现在只能以 1 种方式放置。bag1 中元素的顺序应该相同,并且对于序列中的 bag2 元素也是如此。
因为二叉搜索树的每个子树都必须是 BST。类似的过程将在每个节点上运行,并将节点的本地答案乘以最终答案。
int ans = 1;
int size[1000000] = {0};
// calculate the size of tree and its subtrees before running function "fun" given below.
int calSize(struct node* root){
if(root == NULL)
return 0;
int l = calSize(root->left);
int r = calSize(root -> right);
size[root->val] = l+r+1;
return size[root->val];
}
void fun(struct node* root){
if(root == NULL)
return;
int n = size[root->val];
if(root->left){
ans *= nCr(n-1, size[root->left]);
ans *= 1; // (Just to understand that there is now only 1 way
//to distribute the rest (n-1)-size of root->left)
}
fun(root->left);
fun(root->right);
}
int main(){
struct node* root;
//construct tree
//and send the root to function "fun"
fun(root);
cout<<ans<<endl;
return 0;
}
你可以倒过来做:给定一个 BST,枚举所有可以产生这个 BST 的整数数组......
你不能(使用不确定性......)
非确定性会给你所有这样的数组。然后你可以数一数。