从字符串中删除重复的字符

时间:2017-09-09 20:20:29

标签: c++ string

我想从字符串中删除重复的字符。我使用的逻辑是获取一个字符串,然后将其复制到另一个字符串,然后指向第一个字符串的第一个字符并将其循环通过其他字符串的所有字符,如果相同删除但我在某个地方出错了你可以指导我们

#include<iostream>
#include<string.h>
using namespace std;

int main()
{
    char a[100],b[100];
    cout<<"Enter the string:";
    cin>>a;

    strcpy(b,a);
    int len1=strlen(a);
    int len2=strlen(b);


    for(int i=0;i<len1-1;i++)
    {
        for(int j=i+1;j<len2-1;j++)
        {
            if(a[i]==b[j])
            {
                b[j]=b[j+1];
            }
            len2--;
        }
    }


    cout<<"Without char dupli is:"<<b;
}

6 个答案:

答案 0 :(得分:1)

使用标准库可以做得更好:

  • std::string用于保存字符串而不是字符数组。
  • std::set用于保存已遇到的字符集。
  • std::remove_if使用lambda函数重新组织字符串,以便重复项结束。
  • std::string::erase删除重复项。

以下是此方法的一个示例:

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

int main() {
    std::string str;

    if (!(std::cin >> str)) { return 1; }

    std::set<char> chars;

    str.erase(
        std::remove_if(
            str.begin(),
            str.end(),
            [&chars] (char i) {
                // If encountered character, remove this one.
                if (chars.count(i)) { return true; }

                // Otherwise, mark this character encountered and don't remove.
                chars.insert(i);
                return false;
            }
        ),
        str.end()
    );

    std::cout << str << '\n';

    return 0;
}

Demo

答案 1 :(得分:0)

在你的代码中,当你'删除'一个角色时,你所做的就是复制后面的角色并忽略其他一切。这会导致代码中出现大量错误。删除时,应复制重复字符后的所有字符。

目前删除角色时

    character| -> hharacte|r
    ^             ^<       

你应该做什么

    character| -> haracter|r
    ^             ^<<<<<<<<

另外我认为你需要在b的末尾有一个空字符才能让cout正确打印出来?

(| =通过len2结束字符串, - &gt;删除操作,&lt;复制到上一个点,^替换字符)

答案 2 :(得分:0)

我使用了额外的 O(N)空间(string),解决方案的时间复杂度为 O(N)

# include <iostream>
# include<string>
# include<cstring>        // For memset function
using namespace std;


int main() {
    string s,p;        // s-> original String, p-> extra string(without duplicates)
    cin>>s;
    bool alphabets[26];  // Assuming your string contains charactes between a-z only.
    memset(alphabets,false,26);
    for(int i=0;i<s.size();i++)
    {
        if(alphabets[s.at(i)-'a']==false)    // If that character was marked false i.e if it was not present in original 
        {
            alphabets[s.at(i)-'a']=true;    // mark that character true
            p.push_back(s.at(i));           // Insert that character in string p
        }
    }
    cout<<"Original String: "<<s<<endl; 
    cout<<"String without duplicates: "<<p;
    return 0;
}

Input: 
abcdabasfa

Output: 
Original String: abcdabasfa
String without duplicates: abcdsf

这里是代码Link

答案 3 :(得分:0)

您可以使用这种方式删除重复项,这取决于使用&#39; *&#39;标记副本。但是如果字符串也包含符号,这将不起作用。

#include<iostream>
#include<string.h>
using namespace std;
int main()
{
    char a[100],b[100];
    cout<<"Enter the string:";
    cin>>a;
    strcpy(b,a);
    int len=strlen(a);
    int pointer = 0;
    for(int i=0;i<len;i++)
    {
       if(a[i] == '*')
         continue;

       for(int j=i+1;j<len;j++)
       {
         if(a[i]==b[j])
         {
            a[j]='*';
         }
       }
      b[pointer] = a[i];
      pointer++;
    }
    b[pointer] = '\0';

    cout<<"Without char dupli is:"<<b;
}

此代码为 O(N * N),这会花费大量时间使用长字符串,因此这是优化它的另一种方法:

#include<iostream>
#include<string.h>
#include<set>
using namespace std;
int main()
{
    set<char> containerOfUniqueCharacter;
    char a[100],b[100];
    cout<<"Enter the string:";
    cin>>a;
    strcpy(b,a);
    int len=strlen(a);
    int pointer = 0;
    for(int i=0;i<len;i++)
    {
        //put size of set in a variable 
        //insert char into the set
        //check size of set after inserting
        //if it has changed then it is a new char else it is not
        int testBeforeInsert = containerOfUniqueCharacter.size();
        containerOfUniqueCharacter.insert(a[i]);

        if(containerOfUniqueCharacter.size()!=testBeforeInsert){
         b[pointer] = a[i];
         pointer++;
        }
   }

   //give end to the character array
   b[pointer] = '\0';

   cout<<"Without char dupli is:"<<b;
}

此代码为 O(N),因为在数据结构中插入 O(1)

以上代码使用字符串

#include<iostream>
#include<string.h>
#include<set>
using namespace std;
int main()
{
    //this code works with strings containing all kind of symbols
    set<char> containerOfUniqueCharacter;
    string a,b="";
    cout<<"Enter the string:";
    cin>>a;
    for(int i=0;i<a.size();i++)
    {
        int testBeforeInsert = containerOfUniqueCharacter.size();
        containerOfUniqueCharacter.insert(a[i]);

        if(containerOfUniqueCharacter.size()!=testBeforeInsert){
          b += a[i];
        }
   }
   cout<<"Without char dupli is:"<<b;
}

答案 4 :(得分:0)

C-ish解决方案

我之所以这样,是因为你的代码看起来更像C而不是C ++(同一页面上的strlencout看起来有点可疑)。此解决方案将包含一个127个布尔值(ASCII码为127个字符)的附加数组,用于跟踪您遇到的字符。最初,数组将设置为false,因为我们还没有找到任何字符。此解决方案将为我们节省实际查找字符到另一个数组或使用搜索算法设置所需的开销。请注意,strlen每次调用时都会计算字符串的大小,因此,如果您知道有两个相同大小的字符串,则不要为这两个字符串调用strlen。输入数组中的字符将用作bool数组中的索引。这将起作用,因为字符是整数。所以foundChar[c]几乎可以转化为&#34;是否找到了?&#34;

#include <iostream>
#include <cstring>


int main()
{   
    const int N = 255;
    const int ASCII_CHARS = 127;
    char a[N]; //input string
    bool foundChar[ASCII_CHARS]{ false }; 
    char b[N]; //output string

    std::cin >> a;

    int len = strlen(a);
    int lenb = 0; //b's length(initially 0)

    for (int i = 0; i <= len; i++)
    {
        char c = a[i];
        if (!foundChar[c]) //first char encounter
        {
            b[lenb] = c; 
            lenb++; //we increment it every time we add a character
            foundChar[c] = true; //we found the char
        }
    }

    std::cout << b;

    return 0;
}

你可能已经注意到,在我的for循环中,我写了i <= len,它应该把我带到字符串之外。虽然这是真的,但它不会让我脱离字符串的记忆。 c ++字符串始终以null结尾。这意味着每个字符串都以&#39; \ 0&#39;结尾。这个控制字符告诉我们字符串的结束位置(几乎就是strlen如何计算字符串的大小)。这意味着当我们分配字符串的内存时,我们应该始终记住,存储控制字符所需的额外字节(char[3] c = "abc"会给你一个错误。正确的方法是{{ 1}},&#34; abc&#34;等同于&#34; abc \ 0&#34;)。话虽如此,char[4] c = "abc"为您提供了有用的&#34;字符串的长度,最后没有0。因此,for循环遍历所有字符串的字符,但它也确保复制&#39; \ 0&#39;在b的末尾,因为它本身就是一个字符,strlen在结尾之前都是假的。

关于效果

这是O(N)解决方案。我只使用了127个额外字节的空间(这是无关紧要的)。我不认为你可以从中获得更多的性能,因为必须至少迭代一次字符串。无论如何,我认为这是你想要实现的最干净的方式。

答案 5 :(得分:0)

试试这段代码,它很容易理解和实现。

#include <bits/stdc++.h>
using namespace std;
int main()
{
        string str,temp;
        cin >> str;      
        int n = str.size();               //size of string str store in n
        for(int i=0 ; i<n ; i++)
        {
            temp += str[0];            //append(add) first character of str to string temp
            str.erase(std::remove(str.begin(),str.end(),str[0]),str.end());    //remove same character from string str eg. str[0] = 'a' ; then this line of code remove all 'a' character from string str.
        }
        str = temp;          
        cout << str << endl;          //print string with unique characters
}

这里我们将字符串 str 的第一个字符添加到字符串 temp 并从原始字符串中删除该字符,我们将重复此操作,最后, str 变为空字符串,因为另一方面我们从中删除了所有字符我们在迭代过程中在字符串 temp 中添加唯一字符。