【问题标题】:Function that would accept input with two switched letters?接受两个切换字母输入的函数?
【发布时间】:2015-10-04 00:30:27
【问题描述】:

我想知道如何创建一个可以接受诸如“Computer”之类的输入的函数,或者任何可能的...“Cmoputer”、“romputeC”而不是“Computer”。

//This function would be something like this:
void ignore_switched_letters(char word[]);

int main(){//...}

void ignore_switched_letters(char word[]){
     //... code implimentation...
     char computer[9] = "Computer";
     int length = strlen(computer);
     for (int i = 0; i < length; ++i){
          if (word[i] == 'C'){ ....
          }
     }
}

【问题讨论】:

  • 我已经尝试过遍历字符数组,但我一直在为如何做到这一点而苦苦挣扎。如果我要遍历字符数组“word”中的所有索引并查看它是否匹配所有字母,那将是一团糟。
  • 您只是想忽略一个开关吗?或者任何排列都可以吗?
  • 任何涉及在 2 个字符之间切换的排列。

标签: c++ arrays function char


【解决方案1】:

我建议您将单词放在std::string 中,全部小写。然后您可以使用standard library algorithms 的力量,包括std::mismatch,它返回两个范围不同的第一个位置。您可以检查是否存在两个彼此相反的不匹配。把它写成一个比较两个词的函数可能更灵活:

#include <string>
#include <algorithm>
#include <cassert>

bool compareIgnoreSingleSwitch(const std::string& word1, const std::string& word2) {
  if (word1.size() != word2.size())
    return false;

  auto mismatch1 = std::mismatch(word1.begin(), word1.end(), word2.begin());
  if (mismatch1.first == word1.end())
    return true;  // no mismatches

  auto mismatch2 
    = std::mismatch(std::next(mismatch1.first), word1.end(), std::next(mismatch1.second));

  if (mismatch2.first == word1.end())
    return false;  // only one mismatch, can't be a switch

  // check the two mismatches are inverse of each other
  if (*mismatch1.first != *mismatch2.second || *mismatch1.second != *mismatch2.first)
    return false;

  // ensure no more mismatches  
  return std::equal(std::next(mismatch2.first), word1.end(), std::next(mismatch2.second));
}

int main() {
  assert(compareIgnoreSingleSwitch("computer", "computer"));  // equal
  assert(compareIgnoreSingleSwitch("computer", "pomcuter"));  // one switch
  assert(!compareIgnoreSingleSwitch("computer", "aomxuter"));  // not a switch 
  assert(!compareIgnoreSingleSwitch("computer", "pomputer"));  // one mismatch
  assert(!compareIgnoreSingleSwitch("computer", "ocmupter"));  // two switches
  assert(!compareIgnoreSingleSwitch("computer", "compute"));  // different length    
}

Live demo.

【讨论】:

    【解决方案2】:

    这或多或少 (1) 比较 astrbstr 直到你发现不同。 (2) 记住差异 (3) 继续比较,直到找到第二个 diff (4) 检查第二个 diff 是否与第一个 diff 的逆相匹配 (5) 继续比较。

    int main(int argc,char ** argv) {                                                                                                                                                                                                            
        std::string astr="Computer";                                                                                                                                                                                                             
        if(argc==2) {                                                                                                                                                                                                                            
            std::string bstr(argv[1]);                                                                                                                                                                                                           
    
            // Not the same length == no permutation                                                                                                                                                                                             
            if(astr.size()!=bstr.size()) {                                                                                                                                                                                                       
                std::cerr << "nope" << std::endl;                                                                                                                                                                                                
                return 1;
            }
            int i;
            for(i=0;i<astr.size();i++) {
                if(astr[i]!=bstr[i]) {
                    break;
                }
            }
    
            // We iterated thru == strings are equal
            if(i==astr.size()) {
                std::cerr << "yes" << std::endl;
                return 0;
            }
    
            // We have found the one different char
            // continue iteration and search for the
            // second difference
    
            int j;
    
            for(j=i+1;j<astr.size();j++) {
    
                // another difference
                if(astr[j] != bstr[j]) {
                    // it is the one from astr and vice versa
                    if(astr[i] == bstr[j] && astr[j] == bstr[i]) {
                        break;
                    }
                    // No it isn't
                    std::cerr << "*nope" << std::endl;
                    return 1;
                }
            }
    
            // Didn't find the second difference
            if(j==astr.size()) {
                std::cerr << "nope" << std::endl;
                return 1;
            }
            j++;
            // All others have to be identical
            for(;j<astr.size();j++) {
                if(astr[j] != bstr[j]) {
                    std::cerr << "nope" << std::endl;
                    return 1;
                }
            }
            std::cerr << "yes" << std::endl;
            return 0;
        }
    }
    

    【讨论】:

      【解决方案3】:
      it will return 1 if found else 0
      int ignore_switched_letters(char word[]){
           //... code implimentation...
           char computer[9] = "Computer";
           int length = strlen(computer);
           int flag=1;
           for (int i = 0; i < length; ++i){
                 int falg2=0;
                for (int j = 0; j < length; ++j)
                     if(computer[i]==word[j]){ word[j]=0; falg2=1 }
                  if(0==falg2)
                   {
                     flag=0;
                     break;
                   }
           }
            return flag;
      }
      

      【讨论】:

        【解决方案4】:

        我写了一个代码来验证所需的 char[] 中的 2 个切换字母:

        #include <iostream>
        #include <string.h>
        
        using namespace std;
        
        
        bool is_ignore_switched_letters(char word[]);
        void swapArray(char word[],const int &firstFlag,const int &secondFlag);
        bool isEqual(const char A[] ,const char B[]);
        int main()
        {
        char word[] = "Computre";
        if(is_ignore_switched_letters(word)){
            cout<<"Accepted"<<endl;
        }else{
            cout<<"Rejected"<<endl;
        }
        
        return 0;
        }
        
        bool is_ignore_switched_letters(char word[]){
        
         const char COMPUTER[9] = "Computer";
         int length = strlen(COMPUTER);
        
         int firstFlag = -1;
         int secondFlag = -1;
        
        
         for (int i = 0; i < length; ++i){
        
             if (word[i] != COMPUTER[i] and firstFlag== -1){
                    firstFlag = i;
              }
              else if (word[i] != COMPUTER[i] and secondFlag== -1){
                    secondFlag = i;
              }
        
             if(secondFlag != -1){
                swapArray(word,firstFlag,secondFlag);
                break;
              }
         }
         if(firstFlag==-1 || secondFlag == -1) {
            return false;
         }
         if(isEqual(COMPUTER,word)){
            return true;
         }
         else{
            return false;
         }
        
        }
        
        void swapArray(char word[],const int &firstFlag,const int &secondFlag){
        char buf = word[firstFlag];
        word[firstFlag] = word[secondFlag];
        word[secondFlag] = buf;
        }
        
        bool isEqual(const char A[] ,const char B[]){
        const int lengthA = strlen(A);
        const int lengthB = strlen(B);
        if(lengthA != lengthB) {return false;}
        for(int i = 0 ; i < lengthA ; i++){
            if(A[i]!=B[i]) {return false;}
        }
        return true;
        }
        

        【讨论】:

          【解决方案5】:

          所有这些都非常复杂。您应该坚持使用手头的实用程序。我强烈建议切换到std::string 接口并使用标准库算法。

          以下是我将如何解决您的问题:

          void ignore_switched_letters(const std::string &word){
              static std::string computer = "computer";
              if(!std::is_permutation(std::begin(computer), std::end(computer), std::begin(word)))
                  throw std::runtime_error("string is not a permutation of 'computer'");
          
              // do whatever you like with 'word'
          }
          

          当然你不必抛出异常;但如果性能不是问题,我喜欢。

          更通用的解决方案可能会更好:

          template<typename Functor>
          void ignore_switched_letters(const std::string &check, const std::string &word, Functor &&f){
              if(!std::is_permutation(std::begin(check), std::end(check), std::begin(word)))
                  throw std::runtime_error(word + " is not a permutation of " check);
          
              f();
          }
          

          然后您可以检查多个案例,如下所示:

          int main(){
              std::string computer = "computer";
              std::string chair = "chair";
              std::string microwave = "microwave";
          
              try{
                  ignore_switched_letters(computer, "puterc", [](){
                      std::cout << "is a computer\n";
                  });
          
                  // throws 'std::runtime_error'
                  ignore_switched_letters(chair, "hair", [](){
                      std::cout << "is a chair\n";
                  });
          
                  ignore_switched_letters(microwave, "wavemicro", [](){
                      std::cout << "is a microwave\n";
                  });
              }
              catch(const std::exception &e){
                  std::cerr << e.what() << '\n';
                  exit(EXIT_FAILURE);
              }
          }
          

          这是一个不错的小便利。

          编辑

          我跳过了枪,错过了你只想要 2 个字符的排列,不过我会留下我的答案以引起兴趣。

          【讨论】:

          • OP 只想忽略两个字符之间的切换,而不是任何排列。
          • 哦,我猜有点过头了
          【解决方案6】:

          标准库有很多有用的算法:

          bool compareOnePermutation(std::string s1, std::string s2)
          {
             if (!std::is_permutation(s1.begin(), s1.end(), s2.begin(), s2.end()))
             {
                 return false; // strings contain different letters
             } 
             // Find the differences
             std::transform(s1.begin(),s1.end(),s2.begin(), s1.begin(), std::bit_xor<char>());
             int equal = std:count(s1.begin(),s1.end(), char(0));
             if (equal==s1.size()) return true; // s1==s2
             if (equal==s1.size()-2) return true; // Permutation with 1 swap.
             return false;
          }
          

          使用的技巧是当且仅当 char1==char2 时 char1^char2 == 0。因此,在转换之后,我可以快速数零。当然,自己编写代码效率会稍微高一些,因为您只需要计算差异并在达到 3 时退出:

          // Find the differences
          auto iter2 = s2.begin();
          size_t diff = 0;
          for (char c:s1) {
             if (c != *iter2++) ++diff;
             if (diff==3) return false;
          }
          return diff !=1;
          

          【讨论】:

          • 在调用is_permutation之前是否需要检查s1s2的大小是否相等?
          • @ChrisDrew:问得好,但不是:is_permutation 如果大小不相等,很快 (O(1)) 会返回 false。
          • 没有结束迭代器怎么知道s2的大小?
          • * 天真地吹口哨 *
          • :) ... 请注意,is_permutation 的重载仅适用于 C++14。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-13
          • 2020-02-24
          • 2020-05-20
          • 2013-08-11
          • 1970-01-01
          相关资源
          最近更新 更多