通过在每个位置从特定位置的单词池中选择单词,有效地生成所有序列

Efficiently generating all sequences by selecting word from position specific word pool at each position

本文关键字:位置 有效地 单词 选择 单词池 定位      更新时间:2023-10-16

我有一个类似的特定序列;

x y a
x could represent two words "Xerox" and "Copy".
y could represent three words "china", "DRC" and "Chinese".
a could represent two words "jinx" and "omen"

该序列最多可以由6个单词组成。我有一个从每个项目到向量容器中它的等价字符串的映射。因此,主要目标是通过使用每个项目的不同选项来获得所有可能的单词组合。例如,对于上述情况,所有可能的输出都是。。。

Xerox china jinx
Xerox china omen
Xerox DRC jinx
Xerox DRC omen
Xerox Chinese jinx
Xerox Chinese omen
Copy china jinx
Copy china omen
Copy DRC jinx
Copy DRC omen
Copy Chinese jinx
Copy Chinese omen

目前我正在考虑递归实现,但我无法在我的解决方案中清楚地表达这个想法。我将感谢你的建议和想法。

谢谢。

您实际上并不需要任何递归。

可以列举这样的所有可能性:

  • x的索引可以是零或一
  • y的索引可以是0、1或2
  • a的索引可以是零,也可以是一

通常情况下,您只想在溢出时递增下一个bin,并在最后一个bin溢出时终止循环。想象一下,如果你只有两个选项,每个选项都有一个二进制计数器,你会不断递增,计数器中的每一位都会选择第一个或第二个单词。这也没什么不同。

算法看起来像这样:

Initialize num_lists to number of word lists.
Initialize word lists per position.
Initialize max_count array for the number of words per position.
Initialize count array to all zeros.
Repeat
Print words corresponding to count array (count_array[0] select first word etc.)
Carry = 1 // We're basically adding 1 to our counter
Index = 0
While Carry and Index<num_lists
Add Carry to count[Index]
If count[Index]==max_count[Index] then Carry=1; max_count[Index] = 0
Else Carry = 0
Index = Index + 1
End
While Carry==0

如果您希望代码可读,我认为递归解决方案是一个很好的方法。如果你可以有太多的维度,你显然有栈溢出的风险,但除此之外,我个人更喜欢递归。

下面的代码假设您有一个二维字符串数组,表示为vector < vector<string> >,我称之为v

关键是要跟踪每个维度的索引。我使用一个int数组来实现这一点。假设我知道从每组字符串中我想要哪个字符串,那么很容易打印出来:

void printSequence(const vector< vector<string> > &v, const vector<int> &indices) {
int n = indices.size();
for (int i = 0; i < n; i++) {
cout << v[i][indices[i]];
if (i < n - 1) {
cout << " ";
} else {
cout << endl;
}
}
}

递归调用是构造这样一个数组的简单方法。这里的d代表尺寸。在每个递归级别,我们用一个插入d的元素来填充indices数组。当我们有了所有这些,我们就可以把它们打印出来。

void print(const vector< vector<string> > &v, vector<int> &indices, int d) {
int n = v.size();
if (d == n) {
printSequence(v, indices);
return;
}
for (int i = 0; i < v[d].size(); i++) {
indices.push_back(i);
print(v, indices, d + 1);
indices.pop_back();
}
}

如果你想一想你的例子,最后使用的索引数组会是这样的:

  • 0,0,0
  • 0,0,1
  • 0,1,0
  • 0,1,1
  • 0,2,0
  • 0,2,1
  • 1,0,0
  • 1、2、1

假设您已经填充了v,您可以这样调用print

vector<int> indices;
print(v, indices, 0);

您的问题只是向量x × (y × (a × ...))的笛卡尔乘积,因此以这种方式进行编码可能是直观的。

递归是个好主意,因为问题本质上是递归的。它是foldr,这是一种常见的函数模式,但需要一个初始值(在本例中,是一个带有空字符串的向量)

vector<string> cartesian_concat(const vector<string>& a, 
const vector<string>& b) {
vector<string> result;
for (const string& i : a)
for (const string& j : b)
result.push_back(i + " " + j);
return result;
}
template <typename T, typename U>
U vec_foldr(U (*f)(const T&, const U&), 
const U& init, 
const vector<T>& l, 
unsigned pos=0) {
if (pos < l.size())
return f(l.at(pos), vec_foldr(f, init, l, pos+1));
return init;
}

vector<vector<string>> m {
{ "Xerox", "Copy" },
{ "china", "DRC", "Chinese" },
{ "jinx", "omen" }};
for (const string& i : vec_foldr(cartesian_concat, { "" }, m))
cout << i << endl;
void print(vector<vector<string> >& var, vector<string>& to_print, int level)
{
if(level == var.size() - 1)
{
for(int i = 0; i < var[level].size(); ++i)
{
std::copy(to_print.begin(), to_print.end(), 
ostream_iterator<string>(cout, ","));
cout  << var[level][i] << endl;
}
return;
}
for(int i = 0; i < var[level].size(); ++i)
{
to_print.push_back(var[level][i]);
print(var, to_print, level + 1);
to_print.pop_back();
}
}
int main(int argc, const char * argv[])
{
vector<vector<string> > var;
string X[] = { "Xerorx", "Copy"};
string Y[] = { "china", "DRC", "chinease"};
string Z[] = { "jinx", "omen"};
var.push_back(vector<string>(X, X + 2));
var.push_back(vector<string>(Y, Y + 3));
var.push_back(vector<string>(Z, Z + 2));
vector<string> to_print;
print(var, to_print, 0);
}