如果不使用所有排列强制它,我想不出该怎么做。
类似这样的:
#include <string>
#include <algorithm>
int main()
{
using size_type = std::string::size_type;
std::string word = "overflow";
// examine every permutation of the letters contained in word
while(std::next_permutation(word.begin(), word.end()))
{
// examine each substring permutation
for(size_type s = 0; s < word.size(); ++s)
{
std::string sub = word.substr(0, s);
// look up sub in a dictionary here...
}
}
return 0;
}
我可以想到 2 种方法来加快速度。
1) 检查给定排列的子字符串,以避免不必要的字典查找(std::set 或 std::unordered_set 可能)。
2) 缓存热门搜索结果,保留最常请求的单词(std::map 或 std::unordered_map 可能)。
注意:
事实证明,即使在不同级别添加兑现后,对于较大的单词来说,这确实是一个非常慢的算法。
但是,这使用了更快的算法:
#include <set>
#include <string>
#include <cstring>
#include <fstream>
#include <iostream>
#include <algorithm>
#define con(m) std::cout << m << '\n'
std::string& lower(std::string& s)
{
std::transform(s.begin(), s.end(), s.begin(), tolower);
return s;
}
std::string& trim(std::string& s)
{
static const char* t = " \t\n\r";
s.erase(s.find_last_not_of(t) + 1);
s.erase(0, s.find_first_not_of(t));
return s;
}
void usage()
{
con("usage: anagram [-p] -d <word-file> -w <word>");
con(" -p - (optional) find only perfect anagrams.");
con(" -d <word-file> - (required) A file containing a list of possible words.");
con(" -w <word> - (required) The word to find anagrams of in the <word-file>.");
}
int main(int argc, char* argv[])
{
std::string word;
std::string wordfile;
bool perfect_anagram = false;
for(int i = 1; i < argc; ++i)
{
if(!strcmp(argv[i], "-p"))
perfect_anagram = true;
else if(!strcmp(argv[i], "-d"))
{
if(!(++i < argc))
{
usage();
return 1;
}
wordfile = argv[i];
}
else if(!strcmp(argv[i], "-w"))
{
if(!(++i < argc))
{
usage();
return 1;
}
word = argv[i];
}
}
if(wordfile.empty() || word.empty())
{
usage();
return 1;
}
std::ifstream ifs(wordfile);
if(!ifs)
{
con("ERROR: opening dictionary: " << wordfile);
return 1;
}
// for analyzing the relevant characters and their
// relative abundance
std::string sorted_word = lower(word);
std::sort(sorted_word.begin(), sorted_word.end());
std::string unique_word = sorted_word;
unique_word.erase(std::unique(unique_word.begin(), unique_word.end()), unique_word.end());
// This is where the successful words will go
// using a set to ensure uniqueness
std::set<std::string> found;
// plow through the dictionary
// (storing it in memory would increase performance)
std::string line;
while(std::getline(ifs, line))
{
// quick rejects
if(trim(line).size() < 2)
continue;
if(perfect_anagram && line.size() != word.size())
continue;
if(line.size() > word.size())
continue;
// This may be needed if dictionary file contains
// upper-case words you want to match against
// such as acronyms and proper nouns
// lower(line);
// for analyzing the relevant characters and their
// relative abundance
std::string sorted_line = line;
std::sort(sorted_line.begin(), sorted_line.end());
std::string unique_line = sorted_line;
unique_line.erase(std::unique(unique_line.begin(), unique_line.end()), unique_line.end());
// closer rejects
if(unique_line.find_first_not_of(unique_word) != std::string::npos)
continue;
if(perfect_anagram && sorted_word != sorted_line)
continue;
// final check if candidate line from the dictionary
// contains only the letters (in the right quantity)
// needed to be an anagram
bool match = true;
for(auto c: unique_line)
{
auto n1 = std::count(sorted_word.begin(), sorted_word.end(), c);
auto n2 = std::count(sorted_line.begin(), sorted_line.end(), c);
if(n1 < n2)
{
match = false;
break;
}
}
if(!match)
continue;
// we found a good one
found.insert(std::move(line));
}
con("Found: " << found.size() << " word" << (found.size() == 1?"":"s"));
for(auto&& word: found)
con(word);
}
说明:
此算法通过专注于已知的良好模式(字典单词)而不是排列解决方案生成的大量不良模式来工作。
所以它会在字典中翻找与搜索词匹配的词。随着更明显的词被打折,它会根据准确度提高的测试连续打折。
使用的关键逻辑是搜索每个幸存的字典单词,以确保它包含搜索词中的每个字母。这是通过找到一个字符串来实现的,该字符串包含每个来自搜索词和字典单词的字母。它使用std::unique 来生成该字符串。如果它通过了这个测试,那么它会继续检查字典单词中每个字母的数量是否反映在搜索词中。这使用std::count()。
仅当 所有 字母在字典单词和搜索词中匹配时,才会检测到 perfect_anagram。否则,搜索词包含至少足够的正确字母就足够了。