简体   繁体   English

如何根据一个特定字母的出现来确定两个字符串是否相等?

[英]How to find out if two string are equal based on the occurence of one specific letter?

For this project, two strings are equal if they both have the same number of occurrences of the character 'X' and if the character 'X' is in the same position in each of the strings. 对于此项目,如果两个字符串的字符“ X”的出现次数相同并且字符“ X”在每个字符串中的相同位置,则它们是相等的。 Note that this allows for strings of different lengths as long as the longer string does not have any 'X's in its extra characters at the end. 请注意,这允许使用不同长度的字符串,只要较长的字符串末尾的多余字符中没有任何'X'。 I need to implement this equals function with the function prototype bool equalsChar(const string& strA, const string& strB, char ch) . 我需要使用函数原型bool equalsChar(const string& strA, const string& strB, char ch)实现此equals函数。

Examples 例子

  • equalsChar( "X", "X", 'X' ) is true equalsChar( "X", "X", 'X' )为true
  • equalsChar( "aaaXaaaX", "abcXcbaX", 'X') is true equalsChar( "aaaXaaaX", "abcXcbaX", 'X')为true
  • equalsChar( "XaXbXcX", "XtXoXpXdef", 'X') is true equalsChar( "XaXbXcX", "XtXoXpXdef", 'X')为true
  • equalsChar( "XaXbXcX", "XtXoXpXdXf", 'X') is false equalsChar( "XaXbXcX", "XtXoXpXdXf", 'X')为假
  • equalsChar( "XXXX", "XX", 'X') is false equalsChar( "XXXX", "XX", 'X')为假
  • equalsChar( "aXaXbXcX", "XtXoXpX", 'X') is false equalsChar( "aXaXbXcX", "XtXoXpX", 'X')为假

We can use helper functions, but we are not allowed to allocate any extra memory (eg do not use substring). 我们可以使用辅助函数,但不允许分配任何额外的内存(例如,不要使用子字符串)。 We need to work with indices as we process the strings. 在处理字符串时,我们需要使用索引。

I have tried the knowledge I have so far and looked for similar questions on different websites, but this seems like a unique question. 我已经尝试了到目前为止的知识,并在不同的网站上寻找了类似的问题,但这似乎是一个独特的问题。

Here is the code: 这是代码:

bool equalsChar(const string& strA, const string& strB, char ch){
   int low1=0;
   int low2=0;
   int high1=strA.length()-1;
   int high2=strB.length()-1;
   return equalsChar(strA, low1, high1, strB, low2, high2, ch);
}

I am using an overloaded function: 我正在使用重载函数:

bool equalsChar(const string& strA, int low1, int high1, const string& strB, int low2, int high2, char ch){
   int count1=0;
   int count2=0;
   for(int i=low1; i<=high1; i++){
      if(strA[i]==ch)
         count1++;
   }
   for(int j=low2; j<=high2; j++){
      if(strB[j]==ch)
         count2++;
   }
   if(count1==0 && count2==0)
      return false;
   else if(count1!=count2)
      return false;
   else{
      for(int i=low1; i<=high1; i++){
         if(strA[i]==ch){
            for(int j=low2; j<=high2; j++){
               if(strB[j]==ch){
                  if(i==j)
                     return true;
               }
            }
         }
      }
   }
   return false;
}

There are two problems: 有两个问题:
1. I need to make this code recursively. 1.我需要递归编写此代码。
2. I am only checking for the first character that equals ch from strA and strB and then compare their indices, while what I need to do is to compare for all the Xs in the both strings. 2.我只检查strAstrB中等于ch的第一个字符,然后比较它们的索引,而我需要做的是比较两个字符串中的所有X。

It returns true for equalsChar( "aaaXaaXa", "abcXcbaX", 'X') but it should return false. 对于equalsChar( "aaaXaaXa", "abcXcbaX", 'X') ,它返回true,但应返回false。

First ensure the longer string is strB . 首先确保更长的字符串是strB We use recursion to swap the parameters if needed. 如果需要,我们使用递归交换参数。

Then test common length. 然后测试公共长度。 We project each letter to bool with == ch , and compare those bool s. 我们用== ch将每个字母投影到bool,然后比较这些bool

Finally we test whether ch occurs after strA.size() . 最后,我们测试ch是否在strA.size()之后发生。

bool equalsChar(const string& strA, const string& strB, char ch) {
    if (strA.size() > strB.size()) { return equalsChar(strB, strA, ch); }

    auto common = [ch](char a, char b) { return (a == ch) == (b == ch); };
    return std::equal(strA.begin(), strA.end(), strB.begin(), common)
        && (std::find(strB.begin() + strA.size(), strB.end(), ch) == strB.end());
}

Or with C++17's string_view and a ranges library to tidy up. 或使用C ++ 17的string_view和一个范围库进行整理。

bool equalsChar(string_view strA, string_view strB, char ch) {
    if (strA.size() > strB.size()) { return equalsChar(strB, strA, ch); }

    auto common = [ch](char a, char b) { return (a == ch) == (b == ch); };
    string_view prefix = strB.substr(0, strA.size());
    string_view suffix = strB.substr(strA.size());

    return ranges::equal(strA, prefix, common)
        && !ranges::contains(suffix, ch);
}

In recursive, I would write it: 以递归方式,我会这样写:

// Does s contains given char?
bool hasChar(const char* s, char c)
{
    if (*s == '\0') {
        return false;
    }
    if (*s == c) {
        return true;
    }
    return hasChar(s + 1, c);
}

bool equalsChar(const char* strA, const char* strB, char ch)
{
    // one string is finished, check the other one.
    if (*strA == '\0') {
        return !hasChar(strB, ch);
    } else if (*strB == '\0') {
        return !hasChar(strA, ch);
    }
    // Are strings compare different?
    if (*strA != *strB && (*strA == ch || *strB == ch)) {
        return false;   
    }
    // next index
    return equalsChar(strA + 1, strB + 1, ch);
}

Demo 演示

Ideally you have to 理想情况下,您必须

1. iterate through first string `str1` by i
2. if you encounter `str1[i] == ch`,and 
3    if `i <= str2.length()` 
4.      check if `str2[i] == ch`.  
5.           if false then  strings are not equal
6.   else if `i > str2.length()` you would cut the iteration 
7. else if `str2[i] == ch` then  strings are not equal

8. continue to iterate through string str2 by i, 
9.             if `str2[i] == ch` strings are not equal
A. if end reached , strings are equal.  

Both iterations may be recursive of course, but obviously you need only one index. 当然,这两个迭代都是递归的,但是显然您只需要一个索引。 Alternatively, if that's std::string you can use iterators instead of indexes and passing string\\substring. 或者,如果这是std::string ,则可以使用迭代器代替索引,并传递string \\ substring。 You have to pass str.end() though so iteration would stop when iterator would equal to it. 但是,您必须传递str.end()以便在迭代器等于它时,迭代将停止。

Note , that calling overloaded functions technically is not recursion. 注意,技术上调用重载函数不是递归。 They are different functions. 它们是不同的功能。

Let the first iteration function to be something like 让第一个迭代函数像

bool equalsChar(string::const_iterator& at1, 
                string::const_iterator& at2, 
                const char& ch, 
                const string::const_iterator& end1, 
                const string::const_iterator& end2);

be called like this: 被这样称呼:

bool equalsChar(const string& strA, const string& strB, char ch)
{
     // maybe do checks if strings are empty to shortcut the function?
     auto it1 = strA.begin(), it2 = strB.begin();
     return equalsChar(it1, it2, ch, strA.end(), strB.end() );
}

and would increment iterators while calling itself. 并且会在调用自身时增加迭代器。

Second one would be 第二个是

bool equalsChar(string::iterator& at, 
                const char& ch, const string::iterator& end);

and be called from tail case of the first one 并从第一个的尾巴情况中调用

// assuming we checked that it2 not equal to end2 before
if(it1 == end1) return equalsChar(it2 , ch, end2 );

Now, the cherry. 现在,樱桃。 By required behavior it can be same function with swapped arguments. 通过必需的行为,它可以与交换参数的功能相同。

if(it1 == end1) return equalsChar(it2 , it1, ch, end2, end1 );

And we can do so from start, by checking which string is longer, calling it so first one is always the longer one. 我们可以从头开始,检查哪个字符串更长,然后调用它,这样第一个始终是更长的字符串。

A non-ideal version, is assuming that two string that do not contain X are equal) 非理想版本,假定不包含X的两个字符串相等)

#include <iostream>
#include <vector>
#include <string>

using std::string; 
bool equalsChar(string::const_iterator& at1, 
                string::const_iterator& at2, 
                const char& ch, 
                string::const_iterator& end1, 
                string::const_iterator& end2)
{    
    if(at2 == end2) {
        if(at1 == end1)
            return true; // two empty strings are equal, right?
        if(*at1 == ch)
            return false;    
    }
    else
    { 
        if((*at1 != *at2) && (*at1 == ch || *at2 == ch)) return false; 
        ++at2;
    }

    ++at1;    
    return equalsChar( at1, at2, ch, end1, end2);
}

bool equalsChar(const string& strA, const string& strB, char ch)
{
     // maybe do checks if strings are empty to shortcut the function?
     auto it1 = strA.begin(), it2 = strB.begin();
     decltype(it1) end1 = strA.end(), end2 = strB.end();

     if(strA.length() < strB.length()) 
        std::swap(it1,it2), std::swap(end1,end2);
     return equalsChar(it1, it2, ch, end1, end2 );
}

int main()
{
    std::vector<std::pair<string,string>> data= {
    { "X", "X" },
    { "aaaXaaaX", "abcXcbaX" },
    { "XaXbXcX", "XtXoXpXdef" },
    { "XaXbXcX", "XtXoXpXdXf" },
    { "XXXX", "XX" },
    { "aXaXbXcX", "XtXoXpX" }};


    for(auto& item : data)
        std::cout << "equalsChar( " << item.first << ", " << item.second  << " )" 
              << string{ equalsChar(item.first,item.second,'X') ? " is true" : " is false"} << std::endl;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM