vector<vector<int> > results
for all sequences L in leftSeq
for all sequences R in rightSeq
create a vector flags with l.size() 0's and R.size() 1's
for all permutations of flag
generate the corresponding merged sequence.
append the current node's value in beginning
add this sequence to the results.
return results.
Explanation :让我们从集合 leftSeq 中取一个序列,例如 L(of size n) ,然后从集合 rightSeq 中取一个序列,例如 R(of size m) . 现在这两个序列可以以 m+nCn 方式合并! Proof :合并后,新序列将包含 m + n 个元素 . 由于我们必须保持元素的相对顺序,所以首先我们将在 n 个位置的 n 中填充 L 中的所有元素 . 之后 m 个地方可以填充 R 的元素 . 因此我们必须 choose n places from (m+n) places . 为此,让我们创建一个布尔向量,比如说 flags 并用 n0's 和 m1's 填充它 . 0 的值表示来自 left 序列的成员,值 1 表示来自 right 序列的成员 . 剩下的就是生成所有 permutations 这个标志向量,这可以用 next_permutation 来完成 . 现在,对于每个标志的排列,我们将有一个明确的合并序列 L 和 R . eg: 说 L = {1,2,3} R = {4,5} 所以, n=3 和 m=2 因此,我们可以有 3+2C3 合并序列,即10 . 1.now,最初 flags = {0 0 0 1 1},填充 30's 和 21's 这将导致这个合并的序列: 1 2 3 4 5 2.在调用nextPermutation后我们会有 flags = {0 0 1 0 1} 这将生成序列: 1 2 4 3 5 3.在调用nextPermutation之后我们会有 flags = {0 0 1 1 0} 这将生成序列: 1 2 4 5 3 等等...
Code in C++
vector<vector<int> > findAllSeq(TreeNode *ptr)
{
if (ptr == NULL) {
vector<int> seq;
vector<vector<int> > v;
v.push_back(seq);
return v;
}
if (ptr -> left == NULL && ptr -> right == NULL) {
vector<int> seq;
seq.push_back(ptr -> val);
vector<vector<int> > v;
v.push_back(seq);
return v;
}
vector<vector<int> > results, left, right;
left = findAllSeq(ptr -> left);
right = findAllSeq(ptr -> right);
int size = left[0].size() + right[0].size() + 1;
vector<bool> flags(left[0].size(), 0);
for (int k = 0; k < right[0].size(); k++)
flags.push_back(1);
for (int i = 0; i < left.size(); i++) {
for (int j = 0; j < right.size(); j++) {
do {
vector<int> tmp(size);
tmp[0] = ptr -> val;
int l = 0, r = 0;
for (int k = 0; k < flags.size(); k++) {
tmp[k+1] = (flags[k]) ? right[j][r++] : left[i][l++];
}
results.push_back(tmp);
} while (next_permutation(flags.begin(), flags.end()));
}
}
return results;
}
2 回答
我假设你想要一个生成相同BST的所有序列的列表 .
在这个答案中,我们将使用 Divide and Conquer .
我们将创建一个函数
findAllSequences(Node *ptr)
,它将一个节点指针作为输入,并返回所有不同的序列,这些序列将生成从ptr
挂起的子树 . 此函数将返回Vector of Vector of int,即包含所有序列的vector<vector<int>>
.生成序列的主要思想是 root must come before all its children .
算法:
Base Case 1:
如果
ptr
是NULL
,则返回一个空序列的向量 .Base Case 2:
如果
ptr
是leaf node
,则返回具有单个序列的向量 . 它的琐碎是这个序列只包含一个元素,即该节点的值 .Divide Part (这部分非常简单 . )
我们假设我们有一个可以解决这个问题的函数,因此我们为左子树和右子树解决它 .
Merging the two solutions . (关键在于此步骤 . )
到目前为止,我们有两套不同的序列:
现在左子树中的每个序列可以与右子树的每个序列合并 . 在合并时,我们应该注意保留元素的相对顺序 . 同样在每个合并序列中,我们将在开始时添加当前节点的值beacuse root必须在所有子节点之前 .
Merge的伪代码
Explanation :让我们从集合
leftSeq
中取一个序列,例如L(of size n)
,然后从集合rightSeq
中取一个序列,例如R(of size m)
.现在这两个序列可以以 m+nCn 方式合并!
Proof :合并后,新序列将包含
m + n
个元素 . 由于我们必须保持元素的相对顺序,所以首先我们将在n
个位置的n
中填充L
中的所有元素 . 之后m
个地方可以填充R
的元素 . 因此我们必须choose n places from (m+n) places
.为此,让我们创建一个布尔向量,比如说
flags
并用n
0's
和m
1's
填充它 .0
的值表示来自left
序列的成员,值1
表示来自right
序列的成员 . 剩下的就是生成所有permutations
这个标志向量,这可以用next_permutation
来完成 . 现在,对于每个标志的排列,我们将有一个明确的合并序列L
和R
.eg: 说
L
= {1,2,3}R
= {4,5}所以,
n=3
和m=2
因此,我们可以有 3+2C3 合并序列,即10 .
1.now,最初
flags
= {0 0 0 1 1},填充 30's
和 21's
这将导致这个合并的序列:
1 2 3 4 5
2.在调用nextPermutation后我们会有
flags
= {0 0 1 0 1}这将生成序列:
1 2 4 3 5
3.在调用nextPermutation之后我们会有
flags
= {0 0 1 1 0}这将生成序列:
1 2 4 5 3
等等...
Code in C++
Update 3rd March 2017: 如果原始树包含重复项,此解决方案将无法正常工作 .
这里是我的python代码,它为同一个BST生成所有元素/数字序列 . 对于逻辑我提到了Gayle Laakmann Mcdowell的编码采访