C++ 在单词中查找字谜
Posted
技术标签:
【中文标题】C++ 在单词中查找字谜【英文标题】:C++ Finding Anagrams in words 【发布时间】:2013-09-20 23:07:41 【问题描述】:我正在开发一个程序,该程序使用std:count
查看特定单词是否为字谜,但我认为我的函数逻辑不正确,我似乎无法弄清楚。
假设文件中有以下单词:
Evil
Vile
Veil
Live
我的代码如下:
#include <iostream>
#include <vector>
#include <fstream>
#include <map>
using namespace std;
struct Compare
std::string str;
Compare(const std::string& str) : str(str)
;
bool operator==(const std::pair<int, std::string>&p, const Compare& c)
return c.str == p.second;
bool operator==(const Compare& c, const std::pair<int, std::string>&p)
return c.str == p.second;
std::vector<std::string> readInput(ifstream& file)
std::vector<std::string> temp;
string word;
while (file >> word)
temp.push_back(word);
std::sort(temp.begin(), temp.end());
return temp;
int main(int argc, char *argv[])
string file = "testing.txt";
ifstream ss(file.c_str());
if(!ss.is_open())
cerr << "Cannot open the text file";
std::vector<std::string> words = readInput(ss);
std::map<int, std::string> wordsMap;
//std::map<std::string value, int key> values;
for(unsigned i=0; (i < words.size()); i++)
wordsMap[i] = words[i];
int count = std::count(wordsMap.begin(), wordsMap.end(), Compare("Evil"));
cout << count << endl;
我很确定这只是我的逻辑在函数中错误的一个例子。我希望有人可以提供帮助:)
【问题讨论】:
你不需要std::string
的比较器类,它会为此重载operator==
。
@jrok 感谢您的回复。但是要我确定 Anagram,我需要能够访问 str[i...n] 的元素,对吧?
你能澄清一下吗?您是否试图找出文件中的每个单词是否在同一个文件中有另一个单词是它的字谜?你能提供预期的输出吗?
@masahji 所以这里的预期输出是:3 因为文本文件中的每个单词都是单词“Evil”的变位词
@PHorce 感谢您的澄清。您的文件实际上有 4 行(每行都是“Evil”的字谜,作为参数传递给Compare
)。那么它不会输出 4 吗?
【参考方案1】:
最简单的方法是
检查如下(伪代码)
bool isAnagram(string s, string t) return sort(s) == sort(t);
所以,使用一些像下面这样的想法,不需要std::map
struct Compare
std::string str;
Compare(const std::string& x) : str(x)
std::sort(str.begin(),str.end()); std::transform(str.begin(),
str.end(),str.begin(), ::toupper);
bool operator ()(const std::string& t)
std::string s= t;
std::transform(s.begin(), s.end(),s.begin(), ::toupper);
std::sort(s.begin(),s.end());
return s == str;
;
然后
int count = std::count_if(words.begin(), words.end(), Compare("Evil"));
见HERE
【讨论】:
谢谢。但是,Compare 方法每次都必须排序吗?当使用大值(总字数)时,这变得非常慢.. @Phorce 同意! 但是,例如:int count = std::count_if
因此会在一个 for 循环中,就像这样:for(unsigned i=0; (i < words.begin()); i++) int count = std::count_if(words.begin(), words.end(), Compare(words[i]);
但有些事情似乎不对【参考方案2】:
这不是最有效的算法,但对您的程序进行快速更改可能会起作用:
bool operator==(const std::pair<int, std::string>&p, const Compare& c)
std::string a = c.str;
std::transform(a.begin(), a.end(), a.begin(), ::tolower);
std::sort(a.begin(), a.end());
std::string b = p.second;
std::transform(b.begin(), b.end(), b.begin(), ::tolower);
std::sort(b.begin(), b.end());
return a == b;
【讨论】:
【参考方案3】:编辑:似乎在您当前的代码中,您正在检查字符串是否完全相等(不是字谜)。
代替: 对于每个单词,制作一个包含 26 个元素的数组,每个元素对应于字母表中的一个字母。逐个字符解析每个单词,并增加相应数组中特定字符的计数。
例如对于邪恶,数组将是:
0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0. // It has 1's for letters e,v,i and l
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
你为你拥有的每个单词创建这个数组。在您的情况下,所有单词都将具有相同的数组。然后,您可以逐元素比较这些数组并进行相应的处理。
现在你只需要看看哪些单词有相同的对应数组。
如果您想成对比较所有 N 个单词,您可以使用 O(N^2) 复杂度的两个嵌套循环来实现。 比较一对的复杂度是 O(1)。 创建数组的复杂度 = O(L),其中 L 是字符串的长度。
【讨论】:
不,您需要更改比较函数以检查元素数组而不是字符串本身。 你能举个例子吗?我对创建一个 26 元素数组的确切含义感到困惑,我不明白使用我提供的代码将如何工作。 如果我们遵循您的技术,我认为复杂度是 O(n) 而不是 O(n^2)。原因是我们遍历输入字符串一次以填充上述数组 - 这需要 O(n) 时间。然后我们遍历要测试字谜的字符串一次 - 在最坏的情况下这需要另一个 O(n) 时间。数组元素访问为 O(1),因此每个测试的总体复杂度为 O(n) + O(n) + O(1) = O(n) 是的,你是对的。我说 O(n^2) 是因为我假设所有单词都应该相互比较。 n = 字数(不是字符串长度)。抱歉,我将编辑我的答案。【参考方案4】:考虑以下几点:
map<string, set<string>> anagrams;
for (auto word : words)
anagrams[sort(word)].insert(word);
const set<string>& find_anagrams(const string& word)
return anagrams[word];
【讨论】:
【参考方案5】:当你有很多相对较短的单词时(或者如果你可以使用大量的库),那么你可以使用类似于我在这里写的解决方案 -
Generate same unique hash code for all anagrams
本质上 - 将每个字符映射到一个唯一的素数(不必很大,您可以将整个 ABC 映射到最多 101 个素数),并为每个单词乘以从它接收到的素数字符。由于乘法是可交换的,字谜会给出相同的结果,所以你只需比较该结果,散列它,或做任何你想做的事情
请记住,对于长词,值会增长得非常快,因此您可能需要一个大数字库
【讨论】:
以上是关于C++ 在单词中查找字谜的主要内容,如果未能解决你的问题,请参考以下文章
编写一个字谜查找器(来自 txt 文件中的单词列表)[重复]