比较字符串模式的更好解决方案。?

时间:2020-12-30 07:25:31

标签: c++ algorithm

任务:创建一个函数,如果两个字符串共享相同的字母模式,则返回 true,否则返回 false。

我找到了解决此任务的方法,但我认为它可以更简单、更简短。我将所有相同的字母转换为 2 个字符串的特定字符。然后过程结束检查它们是否相同。有没有更简单的解决方案的想法?

#include <iostream>
#include <string>

using namespace std;

bool LetterPattern(string str1, string str2) { 
    // Controlling whether they have same size or not
    if (str1.length() != str2.length()) {
        return false; 
    }
    else {
        // Checking for ABC XYZ format type 
        int counter = 0;
        for (int i = 0; i < str1.length()-1; i++) {
            for (int k = i+1; k < str1.length(); k++) {
                if (str1[i] == str1[k]) {
                    counter++;
                }
            }
        }
        int counter2 = 0;
        for (int i = 0; i < str2.length() - 1; i++) {
            for (int k = i + 1; k < str2.length(); k++) {
                if (str2[i] == str2[k]) {
                    counter2++;
                }
            }
        }
        
        if (counter == 0 && counter2 == 0) {
            return true;
        }
        // I added the above part because program below couldn't return 1 for completely different letter formats
        // like XYZ ABC DEF etc.
        
        //Converting same letters to same chars for str1
        for (int i = 0; i < str1.length()-1; i++) {
            for (int k = i+1; k < str1.length(); k++) { 
                if (str1[i] == str1[k]) {
                    str1[k] = (char)i;
                }
            }
            str1[i] = (char)i;
        }
    }
    //Converting same letters to same chars for str1
    for (int i = 0; i < str2.length() - 1; i++) {
        for (int k = i + 1; k < str2.length(); k++) { 
            if (str2[i] == str2[k]) {
                str2[k] = (char)i;
            }
        }
        str2[i] = (char)i;
    }
    if (str1 == str2) { // After converting strings, it checks whether they are same or not
        return true;
    }
    else {
        return false;
    }
}
    

int main(){
    cout << "Please enter two string variable: ";
    string str1, str2;
    cin >> str1 >> str2;
    cout << "Same Letter Pattern: " << LetterPattern(str1, str2);

    system("pause>0");
}

示例:

<头>
str1 str2 结果
AABB CCDD 真实
ABAB 疾病预防控制中心 真实
AAFFG AAFGF
asdasd qweqwe 真实

8 个答案:

答案 0 :(得分:3)

如果您想查看一个字符串是否是另一个字符串的凯撒密码,您可以这样做:

bool LetterPatternImpl(const std::string& str1, const std::string& str2) { 
    if (str1.length() != str2.length()) { return false; }

    std::array<std::optional<char>, 256> mapping; // char has limited range,
                                                  // else we might use std::map
    for (std::size_t i = 0; i != str1.length(); ++i) {
        auto index = static_cast<unsigned char>(str1[i]);

        if (!mapping[index]) { mapping[index] = str2[i]; }
        if (*mapping[index] != str2[i]) { return false; }
    }
    return true;
}

bool LetterPattern(const std::string& str1, const std::string& str2) {
    // Both ways needed
    // so ABC <-> ZZZ should return false.
    return LetterPatternImpl(str1, str2) && LetterPatternImpl(str2, str1);
}

答案 1 :(得分:2)

首先,正如您所做的那样,我们可以比较 2 个字符串的大小。 如果它们相等,我们继续。

通过迭代其中 1 个字符串,我们可以填充地图。映射的键是在第一个字符串中看到的字符,它的值是在第二个字符串中对应的字符。

通过到达第 n 个字符,我们检查我们是否有一个键或者与这个字符相同的键。

如果是:检查等于第二个字符串的第n个字符的值。

如果不是:我们向地图添加一个新的键值。 (key为第一个字符串的第n个字符,value为第二个字符串的第n个字符)

1. 完成此操作后,我们应该为另一个字符串再次执行此操作。我的意思是例如,如果在第一步中第一个字符串的字符是键,则在第二步中我们应该以第二个字符串的字符成为键的方式替换字符串。

如果两者都为真,则答案为真。否则为假。

2. 我们可以防止将重复的值添加到映射中,而不是替换字符串并重复迭代。

要理解第 1 段和第 2 段,请想象对“ABC”和“ZZZ”字符串进行 1 次迭代。

请注意,可以使用数组代替映射。

答案 2 :(得分:2)

对字符串进行 1 次迭代,创建定义相应字符的键值对。

在第二次迭代中检查第一个/第二个字符串中的每个字符是否与第二个/第二个字符串中具有相同索引的字符兼容。如果没有不兼容返回true,否则返回false。

答案 3 :(得分:0)

如果我理解正确并且:

AABB - CCDD = true
AAFFG - AAFGF = false
asdasd - qweqwe = true

那不是模式,它检查第二个字符串是否是通过替换第一个加密的结果。您可以通过尝试构建替换表以更简单的方式来完成。如果失败,即源和结果之间存在多个关联,则结果为 false

最简单的情况是我们必须检查整个字符串。如果我们需要发现是否有任何子字符串替换了包含在第二个字符串中的模式,则复杂性平方:

#include <string>
#include <vector>
#include <map>
#include <optional>
#include <limits>

bool is_similar (const std::string& s1, const std::string& s2)
{
    if(s1.length() != s2.length()) return false;
    using TCh = std::decay_t<decltype(s1)>::value_type;
    // for non-unicode characters can use an array
    //std::optional<TCh> table[ std::numeric_limits<TCh>::max ];
    // std::optional used for clarity, in reality may use `TCh`
    // and compare with zero char
    std::map< TCh, std::optional<TCh>> table;
    
    for (size_t it = 0; it < s1.length(); ++it)
    {
       if( table[s1[it]].has_value() && table[s1[it]] != s2[it] ) return false;
       if( table[s2[it]].has_value() && table[s2[it]] != s1[it] ) return false;
       table[s1[it]] = s2[it];
       //table[s2[it]] = s1[it]; if symmetric
    }
    return true;
}

答案 4 :(得分:0)

一个简单(可能不是很有效)的方法:

#include<iostream>
#include<unordered_map>

using namespace std;

int main(void) {
    string s1, s2;
    unordered_map<string, char> subs;

    cout<<"Enter the strings: ";
    cin >> s1 >> s2;
    
    if (s1.length() != s2.length())
        cout<<"False"<<endl;
    else {
        for (int i=0; i<s1.length(); ++i) {
            string key(1, s2[i]);
            subs[key] = s1[i];
        }

        string s1_2 = "";

        for (int i=0; i<s2.length(); ++i) {
            string key(1, s2[i]);
            s1_2 += subs[key];
        }

        if (s1 == s1_2) 
            cout<<"True"<<endl;
        else
            cout<<"False"<<endl;
    }
    return 0;
}


时间复杂度O(n);空间复杂度 O(n)

答案 5 :(得分:0)

不确定更好,而是一个 C++17 解决方案,它基于第一个字符串的字母构建正则表达式并将其与第二个匹配:

void main() {
  final now = DateTime.now().toUtc();
  final minuteAfterNow = new DateTime(now.year,now.month,now.day,now.hour,now.minute +1,now.second,now.millisecond,now.microsecond);
  print(minuteAfterNow);
  print(now);
  print(minuteAfterNow.difference(now));
}

答案 6 :(得分:0)

最后但并非最不重要的是,使用“计数”的附加解决方案。

如果我们阅读了要求,那么您只对布尔结果感兴趣。这意味着,只要我们在第一个字符串中有一个字母的第二个关联,那么结果就是 false

示例:如果我们有一个 'a' 并且在第二个字符串的相同位置有一个 'b',然后在第一个字符串的下一个位置又是一个 'a',但是在第二个字符串的相同位置字符串 a 'c',那么我们对字母 a 有 2 个不同的关联。这是错误的。

如果每个字母只有一个关联,则一切正常。

如何完成“关联”和“计数”。对于“关联”,我们将使用一个关联容器,一个 std::unordered_map。并且,我们将第一个字符串中的一个字母与一个 std::set 已经处理过的字母(来自第二个字符串)相关联。 std::setsiinsert 函数不会从 secondt 字符串添加双字母。因此,如果再次有一个 'b' 与一个 'a' 相关联,那完全没问题。

但是如果有不同的关联字母,那么 std::set 将包含 2 个元素。这是 false 结果的指标。

在这种情况下,我们会立即停止评估字符。这导致代码非常紧凑和快速。

请看:

#include <iostream>
#include <string>
#include <unordered_map>
#include <utility>
#include <set>

bool letterPattern(const std::string& s1, const std::string& s2) {

    // Here we will store the result of the function
    bool result{ s1.length() == s2.length() };

    // And here all associations
    std::unordered_map<char, std::set<char>> association{};

    // Add associations. Stop if result = false
    for (size_t index{}; result && index < s1.length(); ++index)
        if (const auto& [iter, ok] {association[s1[index]].insert(s2[index])}; ok)
            result = association[s1[index]].size() == 1;

    return result;
}
// Some driver test code
int main() {
    std::vector<std::pair<std::string,std::string>> testData{
        {"AABB", "CCDD"},
        {"ABAB", "CDCD"},
        {"AAFFG", "AAFGF"},
        {"asdasd", "qweqwe"}
    };

    for (const auto& p : testData)
        std::cout << std::boolalpha << letterPattern(p.first, p.second) << "\t for: '" << p.first << "' and '" << p.second << "'\n";

    return 0;
}

答案 7 :(得分:0)

如果我们找到一个新字符,我们将使它与其他字符串字符的位置相同。下一次,如果我们再次找到它,我们会根据它进行检查。

假设我们有“aa”和“cd”。
第一次迭代: 'a'='c'
第二次迭代: 已经是 'a'='c'(第一次迭代),所以我们的第二个字符串中必须需要 'c'。
但是在我们的第二个字符串中,它是 'd'。所以它会返回false

#include <bits/stdc++.h>

using namespace std;

// if you want to use map
bool LetterPattern_with_map(string str1,string str2)
{
    if(str1.size()!=str2.size()) return false;
    map<char,char> mp;
    for(int i=0;i<str1.size();i++)
    {
        if(!mp[str1[i]]) { mp[str1[i]]=str2[i]; continue; }
        if(mp[str1[i]]!=str2[i]) return false;
        
    }
    return true;
}

// if you want to use array instead of map
bool LetterPattern_with_array(string str1,string str2)
{
    if(str1.size()!=str2.size()) return false;
    int check[128]={0};
    for(int i=0;i<str1.size();i++)
    {
        if(!check[str1[i]-'A'+1]) { check[str1[i]-'A'+1]=(int)(str2[i]-'A'+1); continue; }
        if(check[str1[i]-'A'+1]!=(int)(str2[i]-'A'+1)) return false;
    }
    return true;
}



int main()
{
    cout << "Please enter two string variable: ";
    string str1, str2;
    cin >> str1 >> str2;
    cout << "Same Letter Pattern: " << LetterPattern_with_map(str1, str2)<<'\n';
    cout << "Same Letter Pattern: " << LetterPattern_with_array(str1, str2);
}
相关问题