检查两个字符串是否是使用C ++的字谜

时间:2013-08-16 06:50:50

标签: c++ string char anagram

我想出了下面的程序来检查两个字符串是否是字谜。它适用于小字符串,但适用于较大的字符串(我试过:听过,入伍)它给我一个'不!'

帮助!

#include<iostream.h> 
#include<string.h>
#include<stdio.h>

int main()
{
    char str1[100], str2[100];
    gets(str1);
    gets(str2);
    int i,j;
    int n1=strlen(str1);
    int n2=strlen(str2);
    int c=0;
    if(n1!=n2)
    {
          cout<<"\nThey are not anagrams ! ";
          return 0;
    }
    else 
    {
         for(i=0;i<n1;i++)
             for(j=0;j<n2;j++)
                 if(str1[i]==str2[j])
                     ++c;
    }
    if(c==n1)
        cout<<"yes ! anagram !! ";
    else 
        cout<<"no ! ";

    system("pause");
    return 0;
}

17 个答案:

答案 0 :(得分:30)

我很懒,所以我会使用标准库功能对两个字符串进行排序,然后比较它们:

#include <string>
#include <algorithm>

bool is_anagram(std::string s1, std::string s2)
{
  std::sort(s1.begin(), s1.end());
  std::sort(s2.begin(), s2.end());
  return s1 == s2;
}

一个小的优化可能是在排序之前检查字符串的大小是否相同。

但是,如果这个算法被证明是瓶颈,我会暂时摆脱一些懒惰并将其与简单的计数解决方案进行比较:

  1. 比较字符串长度
  2. 实例化统计地图std::unordered_map<char, unsigned int> m
  3. 循环s1,增加每个char的计数。
  4. 循环s2,递减每个char的计数,然后检查计数是否为0

答案 1 :(得分:4)

当被要求查找aaaa是否为字谜时,算法也会失败。尝试在心理上或在调试器中跟踪算法的步骤以找出原因;你会从中学到更多。

顺便说一下..查找字谜的常用方法是计算每个字母出现在字符串中的次数。每个字母的计数应相等。与O(n²)相反,这种方法具有O(n)时间复杂度。

答案 2 :(得分:4)

bool areAnagram(char *str1, char *str2)
{
    // Create two count arrays and initialize all values as 0
    int count1[NO_OF_CHARS] = {0};
    int count2[NO_OF_CHARS] = {0};
    int i;

    // For each character in input strings, increment count in
    // the corresponding count array
    for (i = 0; str1[i] && str2[i];  i++)
    {
        count1[str1[i]]++;
        count2[str2[i]]++;
    }

    // If both strings are of different length. Removing this condition
    // will make the program fail for strings like "aaca" and "aca"
    if (str1[i] || str2[i])
      return false;

    // Compare count arrays
    for (i = 0; i < NO_OF_CHARS; i++)
        if (count1[i] != count2[i])
            return false;

    return true;
}

答案 3 :(得分:2)

我看到以下两种主要方法:

  1. 排序然后比较
  2. 计算每个字母的出现次数
  3. 有趣的是,Suraj的好解决方案得到了一点(在我写作的时候),但有一个得到了22分。解释是表现并不是人们的想法 - 这对短篇小说来说很好。

    排序实现只有3行长,但是计数一个对于长字符串来说它是正方形的。它快得多(O(N)对O(NlogN))。 使用500 MB长字符串获得以下结果。

    1. 排序 - 162.8秒
    2. 计数 - 2.864秒
    3. 多线程计数 - 3.321秒
    4. 多线程尝试是一个天真的尝试,试图通过在单独的线程中计数来加倍速度,每个线程一个。内存访问是瓶颈,这是多线程使事情变得更糟的一个例子。

      我很高兴看到一些可以加快计数解决方案的想法(想想一个对内存延迟问题,缓存有好处的人)。

答案 4 :(得分:1)

#include<stdio.h>
#include<string.h>
int is_anagram(char* str1, char* str2){
    if(strlen(str1)==strspn(str1,str2) && strlen(str1)==strspn(str2,str1) &&
    strlen(str1)==strlen(str2))
    return 1;
    return 0;
}
int main(){
    char* str1 = "stream";
    char* str2 = "master";
    if(is_anagram(str1,str2))
    printf("%s and %s  are anagram to each other",str1,str2);
    else
    printf("%s and %s  are not anagram to each other",str1,str2);
    return 0;
}

答案 5 :(得分:1)

#include<iostream>
#include<unordered_map>
using namespace std;

int checkAnagram (string &str1, string &str2)
{
    unordered_map<char,int> count1, count2;
    unordered_map<char,int>::iterator it1, it2;
    int isAnagram = 0;

    if (str1.size() != str2.size()) {
        return -1;
    }

    for (unsigned int i = 0; i < str1.size(); i++) {
        if (count1.find(str1[i]) != count1.end()){
            count1[str1[i]]++;
        } else {
            count1.insert(pair<char,int>(str1[i], 1));
        }
    }

    for (unsigned int i = 0; i < str2.size(); i++) {
        if (count2.find(str2[i]) != count2.end()) {
            count2[str2[i]]++;
        } else {
            count2.insert(pair<char,int>(str2[i], 1));
        }
    }

    for (unordered_map<char, int>::iterator itUm1 = count1.begin(); itUm1 != count1.end(); itUm1++) {
        unordered_map<char, int>::iterator itUm2 = count2.find(itUm1->first);
        if (itUm2 != count2.end()) {
            if (itUm1->second != itUm2->second){
                isAnagram = -1;
                break;
            }
        }
    }

    return isAnagram;
}

int main(void)
{
    string str1("WillIamShakespeare");
    string str2("IamaWeakishSpeller");

    cout << "checkAnagram() for " << str1 << "," << str2 << " : " << checkAnagram(str1, str2) << endl;

    return 0;
}

答案 6 :(得分:1)

有时最好的问题是最简单的,这很有趣。

这里的问题是如何推断出两个单词是否是字谜 - 一个单词基本上是一个未分类的字符集。

我们知道我们必须排序,但理想情况下我们希望避免排序的时间复杂性

事实证明,在很多情况下,我们可以通过遍历它们并将字符值异或缩放到累加器中来消除许多在线性时间中不相似的单词。如果两个字符串都是字谜,则两个字符串中所有字符的总XOR必须为零,无论顺序如何。这是因为任何与自身相关的东西都变为零。

当然反之亦然。仅仅因为累加器为零并不意味着我们有一个anagram匹配。

使用这些信息,我们可以消除许多非字谜,而不是至少非anagram案例的短路。

#include <iostream>
#include <string>
#include <algorithm>

//
// return a sorted copy of a string
//
std::string sorted(std::string in)
{
    std::sort(in.begin(), in.end());
    return in;
}

//
// check whether xor-ing the values in two ranges results in zero.
// @pre first2 addresses a range that is at least as big as (last1-first1)
//
bool xor_is_zero(std::string::const_iterator first1,
                 std::string::const_iterator last1,
                 std::string::const_iterator first2)
{
    char x = 0;
    while (first1 != last1) {
        x ^= *first1++;
        x ^= *first2++;
    }
    return x == 0;
}

//
// deduce whether two strings are the same length
//
bool same_size(const std::string& l, const std::string& r)
{
    return l.size() == r.size();
}

//
// deduce whether two words are anagrams of each other
// I have passed by const ref because we may not need a copy
//
bool is_anagram(const std::string& l, const std::string& r)
{
    return same_size(l, r)
    && xor_is_zero(l.begin(), l.end(), r.begin())
    && sorted(l) == sorted(r);
}

// test

int main()  {

    using namespace std;

    auto s1 = "apple"s;
    auto s2 = "eppla"s;

    cout << is_anagram(s1, s2) << '\n';

    s2 = "pppla"s;

    cout << is_anagram(s1, s2) << '\n';

    return 0;
}

预期:

1
0

答案 7 :(得分:1)

这是检查字谜的最简单,最快捷的方法

bool anagram(string a, string b) {
    int a_sum = 0, b_sum = 0, i = 0;
    while (a[i] != '\0') {
        a_sum += (int)a[i]; // (int) cast not necessary
        b_sum += (int)b[i];
        i++;
    }
    return a_sum == b_sum;
}

只需添加ASCII值并检查总和是否相等。

例如: 字符串a =&#34; nap&#34;和字符串b =&#34; pan&#34;
     a_sum = 110 + 97 + 112 = 319
     b_sum = 112 + 97 + 110 = 319

答案 8 :(得分:0)

在这种方法中,我处理空字符串和重复字符。享受它并评论任何限制。

#include <iostream>
#include <map>
#include <string>

using namespace std;

bool is_anagram( const string a, const string b ){
    std::map<char, int> m;
    int count = 0;

    for (int i = 0; i < a.length(); i++) {
        map<char, int>::iterator it = m.find(a[i]);
        if (it == m.end()) {
            m.insert(m.begin(), pair<char, int>(a[i], 1));
        } else {
            m[a[i]]++;
        }
    }

    for (int i = 0; i < b.length(); i++) {
        map<char, int>::iterator it = m.find(b[i]);
        if (it == m.end()) {
            m.insert(m.begin(), pair<char, int>(b[i], 1));
        } else {
            m[b[i]]--;
        }
    }

    if (a.length() <= b.length()) {
        for (int i = 0; i < a.length(); i++) {
            if (m[a[i]] >= 0) {
                count++;
            } else
                return false;
        }
        if (count == a.length() && a.length() > 0)
            return true;
        else
            return false;
    } else {
        for (int i = 0; i < b.length(); i++) {
            if (m[b[i]] >= 0) {
                count++;
            } else {
                return false;
            }
        }
        if (count == b.length() && b.length() > 0)
            return true;
        else
            return false;
    }
    return true;
}

答案 9 :(得分:0)

试试这个:

// Anagram. Two words are said to be anagrams of each other if the letters from one word can be rearranged to form the other word. 
// From the above definition it is clear that two strings are anagrams if all characters in both strings occur same number of times. 
// For example "xyz" and "zxy" are anagram strings, here every character 'x', 'y' and 'z' occur only one time in both strings. 

#include <map>
#include <string>
#include <cctype>
#include <iostream> 
#include <algorithm>
#include <unordered_map>

using namespace std;

bool IsAnagram_1( string w1, string w2 )
{
    // Compare string lengths
    if ( w1.length() != w2.length() )
        return false;

    sort( w1.begin(), w1.end() );
    sort( w2.begin(), w2.end() );

    return w1 == w2;
}

map<char, size_t> key_word( const string & w )
{
    // Declare a map which is an associative container that will store a key value and a mapped value pairs
    // The key value is a letter in a word and the maped value is the number of times this letter appears in the word
   map<char, size_t> m;

   // Step over the characters of string w and use each character as a key value in the map
   for ( auto & c : w )
   {
        // Access the mapped value directly by its corresponding key using the bracket operator
        ++m[toupper( c )];  
   }

   return ( m );
}


bool IsAnagram_2( const string & w1, const string & w2 )  
{
    // Compare string lengths
    if ( w1.length() != w2.length() )
        return false;

    return ( key_word( w1 ) == key_word( w2 ) );
}


bool IsAnagram_3( const string & w1, const string & w2 )  
{
    // Compare string lengths
    if ( w1.length() != w2.length() )
        return false;

    // Instantiate a count map, std::unordered_map<char, unsigned int> m
    unordered_map<char, size_t> m;

    // Loop over the characters of string w1 incrementing the count for each character
   for ( auto & c : w1 )
   {
        // Access the mapped value directly by its corresponding key using the bracket operator
        ++m[toupper(c)];    
   }

    // Loop over the characters of string w2 decrementing the count for each character
   for ( auto & c : w2 )
   {
        // Access the mapped value directly by its corresponding key using the bracket operator
        --m[toupper(c)];    
   }

   // Check to see if the mapped values are all zeros
   for ( auto & c : w2 )
   {
        if ( m[toupper(c)] != 0 )
            return false;
   }

   return true;
}


int main( )
{
    string word1, word2;

    cout << "Enter first word: ";
    cin >> word1;

    cout << "Enter second word: ";
    cin >> word2;

    if ( IsAnagram_1( word1, word2 ) )
        cout << "\nAnagram" << endl;
    else 
        cout << "\nNot Anagram" << endl;


    if ( IsAnagram_2( word1, word2 ) )
        cout << "\nAnagram" << endl;
    else 
        cout << "\nNot Anagram" << endl;


    if ( IsAnagram_3( word1, word2 ) )
        cout << "\nAnagram" << endl;
    else 
        cout << "\nNot Anagram" << endl;

    system("pause");

    return 0;
}

答案 10 :(得分:0)

检查两个字符串是否对每个唯一字符具有相同的计数。

bool is_Anagram_String(char* str1,char* str2){

    int first_len=(int)strlen(str1);
    int sec_len=(int)strlen(str2);

    if (first_len!=sec_len) 
         return false;

    int letters[256] = {0};

    int num_unique_chars = 0;
    int num_completed_t = 0;

    for(int i=0;i<first_len;++i){
        int char_letter=(int)str1[i];
        if(letters[char_letter]==0)
            ++num_unique_chars;
        ++letters[char_letter];
    }

    for (int i = 0; i < sec_len; ++i) {

        int c = (int) str2[i];

        if (letters[c] == 0) { // Found more of char c in t than in s.
            return false;
        }

        --letters[c];

        if (letters[c] == 0) {

            ++num_completed_t;

            if (num_completed_t == num_unique_chars) {
                // it’s a match if t has been processed completely
                return i == sec_len - 1;
            }
        }
   }
    return false;}

答案 11 :(得分:0)

#include <iostream>
#include <string.h>

using namespace std;

const int MAX = 100;

char cadA[MAX];
char cadB[MAX];
bool chrLocate;


int i,m,n,j, contaChr;

void buscaChr(char [], char []);

int main() {

    cout << "Ingresa CadA: ";
    cin.getline(cadA, sizeof(cadA));
    cout << "Ingresa CadB: ";
    cin.getline(cadB, sizeof(cadA));    

    if ( strlen(cadA) == strlen(cadB) ) {

        buscaChr(cadA,cadB);        

    } else {
        cout << "No son Anagramas..." << endl;
    }

    return 0;
}


void buscaChr(char a[], char b[]) {

    j = 0;  
    contaChr = 0;

    for ( i = 0; ( (i < strlen(a)) && contaChr < 2 ); i++ ) {

        for ( m = 0; m < strlen(b); m++ ) {

            if ( a[i] == b[m]) {
                j++;
                contaChr++;
                a[i] = '-';
                b[m] = '+';
            } else { contaChr = 0;  }
        }       
    }

    if ( j ==  strlen(a)) {
        cout << "SI son Anagramas..." << endl;
    } else {
        cout << "No son Anagramas..." << endl;
    }

}

答案 12 :(得分:0)

您的算法不正确。您正在检查第一个单词中的每个字符,以查看该字符在第二个单词中出现的次数。如果这两个单词是&#39; aaaa&#39;和&#39; aaaa&#39;那么这会给你16个计数。对你的代码做一个小改动就可以让它工作,但是会给你一个复杂的N ^ 2,因为你有一个双循环。

for(i=0;i<n1;i++)
for(j=0;j<n2;j++)
if(str1[i]==str2[j])
++c, str2[j] = 0; // 'cross off' letters as they are found.

我用anagram比较做了一些测试。比较两个每个72个字符的字符串(字符串总是真正的字谜以获得最大数量的比较),使用几个不同的STL容器执行256次相同测试......

template<typename STORAGE>
bool isAnagram(const string& s1, const string& s2, STORAGE& asciiCount)
{
    for(auto& v : s1)
    {
        asciiCount[v]++;    
    }
    for(auto& v : s2)
    {
        if(--asciiCount[static_cast<unsigned char>(v)] == -1)
        {
            return false;
        }
    }

    return true;
}

STORAGE asciiCount =

map<char, int> storage;           // 738us 
unordered_map<char, int> storage; // 260us 
vector<int> storage(256);         // 43us

// g ++ -std = c ++ 17 -O3 -Wall -pedantic

这是我能得到的最快的。

  • 这些是使用coliru在线编译器+和std :: chrono :: steady_clock :: time_point进行测量的原始测试,但是它们提供了性能增益的一般概念。
  • vector具有相同的性能,仅使用256个字节,尽管字符串的长度限制为255个字符(也改为: - asciiCount [static_cast(v)] == 255 for unsigned char counting)。
  • 假设矢量最快。一个改进就是只分配一个C样式数组unsigned char asciiCount [256];在堆栈上(因为STL容器在堆上动态分配它们的内存)
  • 您可以将此存储空间减少到128个字节,64个甚至32个字节(ascii字符通常在0..127范围内,而A-Z + az 64.127,只是大写或小写64..95或96 ... 127)虽然不确定在高速缓存行或半数内部装入这些内容会有什么收益。

有更好的方法吗?对于速度,记忆,代码优雅?

答案 13 :(得分:0)

1。删除匹配字符的简单快捷方法

bool checkAnagram(string s1, string s2) {
    for (char i : s1) {
        unsigned int pos = s2.find(i,0);
        if (pos != string::npos) {
            s2.erase(pos,1);
        } else {
            return false;
        }
    }
    return s2.empty();
}

2。转换为素数。漂亮但非常昂贵,需要特殊的Big Integer类型才能使用长字符串。

// https://en.wikipedia.org/wiki/List_of_prime_numbers
int primes[255] = {2, 3, 5, 7, 11, 13, 17, 19, ... , 1613}; 

bool checkAnagramPrimes(string s1, string s2) {
    long c1 = 1;
    for (char i : s1) {
        c1 = c1 * primes[i];
    }
    long c2 = 1;
    for (char i : s2) {
        c2 = c2 * primes[i];
        if (c2 > c1) {
            return false;
        }
    }
    return c1 == c2;
}

答案 14 :(得分:0)

void write_announcement()
{
    student st;          
    string line;
    int num;

    ofstream file;
    file.open("announcement.txt");

    cout << "Enter number:";
    cin >> num;

    cin.ignore();
    getline(cin,line);

    announce[num] = line;
    file.write(reinterpret_cast<char *> (&st), sizeof(student));

    file.close();
}    

void read_announcement()
{
    student st;
    int n;
    cout << "Enter n: ";
    cin >> n;

    ifstream file;
    file.open("announcement.txt");

    while (file >> st.announce[n]);
    {
       cout << announce[n];
    }

    file.close();
}

答案 15 :(得分:0)

而不使用在现代c ++中已弃用的dot h标头。

尝试此解决方案。

        #include <iostream>
        #include <string>
        #include <map>

        int main(){
          std::string word_1 {};
          std::cout << "Enter first word: ";
          std::cin >> word_1;

          std::string word_2 {};
          std::cout << "Enter second word: ";
          std::cin >> word_2;

          if(word_1.length() == word_2.length()){
            std::map<char, int> word_1_map{};
            std::map<char, int> word_2_map{};
            for(auto& c: word_1)
              word_1_map[std::tolower(c)]++;
            for(auto& c: word_2)
              word_2_map[std::tolower(c)]++;
            if(word_1_map == word_2_map){
              std::cout << "Anagrams" << std::endl;
            }
            else{
              std::cout << "Not Anagrams" << std::endl;
            }
          }else{
            std::cout << "Length Mismatch" << std::endl;
          }
        }

答案 16 :(得分:0)

#include <bits/stdc++.h>
using namespace std;
#define NO_OF_CHARS 256

int main()
{   bool ans = true;
    string word1 = "rest";
    string word2 = "tesr";
    unordered_map<char,int>maps;
    for(int i = 0 ; i <5 ; i++)
    {
        maps[word1[i]] +=1;

    }
    for(int i = 0 ; i <5 ; i++)
    {
        maps[word2[i]]-=1 ;

    }

    for(auto i : maps)
    {
        if(i.second!=0)
        {
            ans = false;
        }
    }

    cout<<ans;
}