查找字符串的所有可能版本,其字符可能具有多个变体

Find all possible versions of a string whose characters may have multiple variants

本文关键字:字符 字符串 有可能 版本 查找      更新时间:2023-10-16

我正在寻找一些有关如何查找字符串的所有可能版本的提示,这些字符串的字符可能具有多个变体。

一个简单的例子:"澳门"是起始字符串。字符"a"具有变体"ä",字符"o"具有变体"ö"。

目标是从上述信息中获取以下列表:

Macao
Mäcao
Macäo
Mäcäo
Macaö
Mäcaö
Macäö
Mäcäö

到目前为止,我的方法是识别和提取带有变体的字符以简化事情。这个想法是在各自的字符上工作,而不是整个单词。

aao
äao
aäo
ääo
aaö
äaö
aäö
ääö

以下代码查找我们正在使用的变体。

std::vector<std::string> variants;
variants.push_back("aä");
variants.push_back("oö");
std::string word = "Macao";
std::vector<std::string> results;
for (auto &variant : variants) {
    for (auto &character : word) {
        if (variant.front() == character) {
            results.push_back(variant);
        }
    }
}
std::cout << "The following characters have variants: ";
for (auto &i : results) {
    std::cout << i.front();
}
std::cout << std::endl;

下一步是找到相应字符的所有可能组合。为此,我编写了以下函数。它从 results 中每个字符串的第一个字符创建一个新字符串。

std::string read_results(std::vector<std::string> &results)
{
    std::string s;
    for (auto &c : results) {
        s.push_back(c.front());
    }
    return s;
}

这个想法是然后以这样一种方式更改存储在results中的字符串,以获得所有可能的组合,这就是我卡住的地方。我注意到std::rotate似乎会有所帮助。

排索引可能很有用。

您可以按顺序将具有多个变体的所有字母按顺序存储在一个向量中,并且每个字母都有一个分组索引的向量,以便第 i 个字母属于组I[i],并且索引与 I[i] 相同的所有字母都是来自同一字母的变体:

string L = "aoäöâô"; // disclaimer: i don't know if this is really in order
unsigned int I[]  = {0,1,0,1,0,1};
// this means that "aäâ" belong to group 0, and "oöô" belong to group 1

您可以为前一个L构建倒排索引,并使用如下所示的内容进行I

vector<vector<unsigned int> > groups;
// groups[k] stores the indices in L of the letters that belongs to the k-th group.
// do groups.reserve to make this operation more efficient
for(size_t i = 0; i < L.size(); ++i)
{
  unsigned int idx = I[i];
  if(idx <= groups.size()) groups.resize(idx+1);
  groups[idx].push_back(i);
}

重要的是,L中的字母是有序的,所以你可以稍后对它进行二叉搜索,这需要O(logn)而不是O(n)通常的循环。然后,一旦你有了你的字母组,你就可以找到它的变体,有一个倒排索引:

char letter = 'a';
string::iterator it = std::lower_bound(L.begin(), L.end(), letter);
if(it != L.end() && *it == letter)
{
  unsigned int idx = I[ it - L.begin() ];
  // the letter has variants because it belongs to group idx
  const vector<unsigned int>& group = groups[idx];
  for(vector<unsigned int>::const_iterator git = group.begin();
    git != group.end(); ++git)
  {
    // now, L[*git] is one of the variants of letter
    ...
  }
}