【问题标题】:Remove duplicates from the string in CPP从 CPP 中的字符串中删除重复项
【发布时间】:2020-05-31 12:28:21
【问题描述】:

我编写了以下代码来删除给定字符串中的重复项,即如果 ARRUN 是输入,那么输出将为 ARUN。

#include <bits/stdc++.h>
using namespace std;
char* removeDuplicates(string &s,int n){
    char arr[n];
    unordered_map<char,int> exists;
    int index = 0;
    for(int i=0;i<n;i++){
        if(exists[s[i]]==0)
        {
            arr[index++] = s[i];
            exists[s[i]]++;
        }
    }
    return arr;
}

//driver code
int main(){
    string str;
    cin >> str;
    cout<<removeDuplicates(str,str.length())<<endl;
    return 0;
}

该代码根本不产生任何输出,但是,如果我使用 char arr[] 而不是字符串类,它可以正常工作。

【问题讨论】:

  • 您不能从 C++ 函数返回自动(非静态)数组。数组不是 C++ 中的第一类对象。
  • @Arun Suryan 您需要删除相邻的重复字符还是所有重复字符?
  • 所有重复字符。
  • 你应该永远 #include &lt;bits/stdc++.h&gt;。这不仅仅是不好的做法——它不是正确的 C++。它破坏了便携性并养成了糟糕的习惯。通过使用它,您不仅授予编译器在不通知的情况下随时破坏您的代码的权利,而且还使您的代码不可移植和不专业。它还创建了对 C++ 标准库的任何未来设施的隐式依赖,从而基本上搞砸了编译时间。见Why should I not #include &lt;bits/stdc++.h&gt;

标签: c++ string algorithm stl


【解决方案1】:

这也适用,具有内置功能的单行解决方案。

cout&lt;&lt;str.erase(std::unique(str.begin(), str.end()), str.end());

【讨论】:

    【解决方案2】:

    如果不是n 常量或constexpr,则不能使用char arr[n]

    您不需要mapset 就足够了。

    注意mapset已经删除了重复项,然后你可以检查是否插入了任何元素以与第一个相同的顺序获取你的新字符串,如下

    #include<string>
    #include<iostream>
    #include<unordered_set>
    
    std::string removeDuplicates(const std::string &s){
        std::string arr;
        std::unordered_set<char> exists;
    
        for(const auto&el:s)
            if(exists.insert(el).second) arr+=el;
    
        return arr;
    }
    
    //driver code
    int main(){
        std::string str;
        std::cin >> str;
        std::cout<<removeDuplicates(str)<<std::endl;
        return 0;
    }
    

    【讨论】:

    • 我喜欢你的编码风格。但是我只是懒得一次又一次地写std::bits/stdc++.h 完成工作。不过,我知道这不是一个好习惯。
    • @ArunSuryan 除了只有一个编译器行得到了那个头文件
    • @ArunSuryan bits/stdc++.h 完成工作 -- 请阅读this
    • 在体育节目中非常重要。这就是我经常使用它的原因。它节省了打字工作。
    • 还有read this。如果您编写的代码使用data 作为结构类型或类似的类型,您的“体育编程”头文件将会失败。
    【解决方案3】:

    这对于 C++ 的新手来说可能有点高级,但另一个解决方案使用了erase-remove idiom

    std::string removeDuplicates(const std::string& s) {
        std::string result = s;
        std::unordered_set<char> seen;
    
        result.erase(std::remove_if(result.begin(), result.end(), [&seen](char c)
            {
                if (seen.find(c) != seen.end())
                    return true;
    
                seen.insert(c);
                return false;
            }),
        result.end());
    
        return result;
    }
    

    它基本上使用一个集合来存储已经看到的字符,将要删除的字符打乱到尾部(使用std::remove_if)并从字符串中删除尾部。

    工作版here.

    【讨论】:

      【解决方案4】:

      @Arun Suryan,您指出的正确。但是您可以通过使用 global char array 来做到这一点而不使用矢量。

      另外别忘了在末尾附加newline

      看看下面的代码:

      #include<string>
      #include<iostream>
      #include<unordered_map>
      
      char* removeDuplicates(std::string &s,int n){
      
          std::unordered_map<char,int> exists;
          char* arr = (char*)(malloc(n*sizeof(char)));
          int index = 0;
          for(int i=0;i<n;i++){
              if(exists[s[i]]==0)
              {
                  arr[index++] = s[i];
                  exists[s[i]]++;
              }
          }
          arr[index] = '\n';
          return arr;
      }
      
      //driver code
      int main(){
          std::string str;
          std::cin >> str;
          std::cout<<removeDuplicates(str,str.length())<<std::endl;
          return 0;
      }
      

      【讨论】:

      • 是的,你可以,但是通过全局变量返回值而不需要这样做是 Fortran-77 编程风格(因为 Fortran 没有其他方法)。 vector 使用堆,它是全局的,但象征性地管理器对象获得了一定的位置和身份。在大型项目中,使用全局静态变量成为真正的威胁,C++ 和类似的命令式语言的反对者指出了这一点。
      • @Swift-FridayPie 同意!
      • 对不起,我不得不拒绝你的答案,因为它促进了全局变量和具有固定大小的原始 C 数组的使用(从而导致有保证的缓冲区溢出),它们都不兼容现代 C++编程实践。此外,这种方法显着增加了代码分析的难度(“某些函数是否只是修改了该全局变量?”),更不用说引入数据竞争了。始终使用std::string 和值语义。这甚至不算#include &lt;bits/stdc++.h&gt;using namespace std;
      • @L.F.不用担心!已采纳建议!
      • malloc 同样糟糕。您应该使用 std::string 而不是手动分配的(或固定大小的)char 数组。实际上,您现在正在泄漏分配,而没有放置新的malloc 在技术上(当前)始终是未定义的行为。没有理由在new[] 上使用它。
      【解决方案5】:

      std::string 支持删除元素。

      #include <iostream>
      #include <string>
      
      std::string removeDuplicates(std::string str) {
          for (int i = 0; i < str.size(); i++) {
              while (true) {
                  int j = str.find_last_of(str[i]);
                  if (i < j) {
                      str.erase(j, 1);
                  } else {
                      break;
                  }
              }
          }
          return str;
      }
      
      int main() {
          std::cout << removeDuplicates("ARRUN");
          return 0;
      }
      

      【讨论】:

        【解决方案6】:

        如果函数声明如下所示

        char* removeDuplicates(string &s,int n);
        

        那么就表示传入的对象本身会在函数中发生变化。否则参数应具有限定符 const。

        还不清楚为什么函数返回类型为char *。看来函数的声明是矛盾的。

        函数的第二个参数至少应具有size_t 或更好的std::string::size_type 类型。 int 类型不能容纳 std::string::size_type 类型的所有值。

        函数可以在没有第二个参数的情况下声明。

        不使用需要动态内存分配的中间容器的简单方法如下所示

        #include <iostream>
        #include <string>
        
        std::string & removeDuplicate( std::string &s )
        {
            const char *p = s.c_str();
        
            std::string::size_type pos = 0;
        
            for ( std::string::size_type i = 0, n = s.size(); i < n; i++ )
            {
                std::string::size_type j = 0;
                while ( j < pos && s[i] != s[j] ) j++;
        
                if ( j == pos )
                {
                    if ( i != pos ) s[pos] = s[i];
                    ++pos;
                }
            }
        
            return s.erase( pos );
        }
        
        int main() 
        {
            std::string s( "H e l l o" );
        
            std::cout << "\"" << s <<"\"\n";
        
            std::cout << "\"" << removeDuplicate( s ) <<"\"\n";
        
            return 0;
        }
        

        程序输出是

        "H e l l o"
        "H elo"
        

        【讨论】:

          【解决方案7】:

          所以,在网上做了一些阅读之后,我意识到我试图在removeDuplicates() 函数中返回一个指向本地数组的指针。

          这很好用

          #include <bits/stdc++.h>
          using namespace std;
          void removeDuplicates(string &s,int n){
              vector<char> vec;
              unordered_map<char,int> exists;
              int index = 0;
              for(int i=0;i<n;i++){
                  if(exists[s[i]]==0)
                  {
                      vec.push_back(s[i]);
                      exists[s[i]]++;
                  }
              }
              for(auto x: vec)
                  cout << x;
          }
          
          //driver code
          int main(){
              string str;
              cin >> str;
              removeDuplicates(str,str.length());
              return 0;
          }
          

          PS:我们也可以将函数的返回类型设为vector。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-04-03
            • 1970-01-01
            • 1970-01-01
            • 2011-02-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多