1. 程式人生 > >一道演算法題---把字串內連續相同字元刪除

一道演算法題---把字串內連續相同字元刪除

題目描述:

給定一字串,刪除連續相同的字元,如baiidu刪除後為badu,baiiiau刪除後為bu,baiiabdu刪除後為du。

要做這道題,大家可能第一想法就是找到連續相同字元,然後刪除,把後續字元前移,然後繼續。不斷迭代,直到不再有連續字元為止。這種演算法效率比較低。

仔細觀察發現,其實就是刪除迴文子串問題(但是還有些不一樣,像bab這種迴文串,按題目要求是不能刪除的)。關於迴文子串的演算法,可以看本部落格中的Manacher演算法一章

像baiiabdu可以轉換成

 str[] = $    #    b    #    a    #    i    #    i    #    a    #    b    #    d    #    u    #

p[]   = 0    1    2    1    2    1    2   7    2   1    2    1    2    1    2    1    2    1

下面p陣列代表上面相應字元為中心的迴文子串長度。 

我們發現要刪除的子串都是以#為中心的長度大於等於3的迴文子串,或者以字母為中心的長度大於等於4的並且該字母與相鄰的兩個字母相同的迴文子串。那我們就掃描str陣列,把以#為中心的長度為奇數的迴文子串全部置為#。處理後的str為 $    #    #    #    #    #    #    #    #    #    #    #    #    #    d    #    u    #

然後輸出從下標1開始的不為#字元的所有字元,即du。

對於baiiiau,奇數連續相同字元,也是能處理的。

 str[] = $    #    b    #    a    #    i    #    i    #    i     #    a    #    u    #

p[]   = 0    1    2    1    2    1    2   3    6   3    2    1    2    1    2    1

處理後的str為$    #    b    #    #    #    #    #    #    #    #     #    #    #    u    #

下面附上程式碼:

/*問題描述:給定一字串,刪除連續相同的字元,如baiidu刪除後為badu,baiiad刪除後為bd*/

#include <iostream>
#include <cstring>
using namespace std;

/*尋找最長迴文子串,Manacher演算法描述http://blog.csdn.net/ggggiqnypgjg/article/details/6645824,
把偶數長度的迴文子串進行刪除*/
char* Manacher(char *src)
{
    char *str = new char[2*strlen(src)+3];
    char *str2 = new char[2*strlen(src)+3];
    str[0] = '$';
    str2[0] = '$';
    int i = 1;
    while(*src != '\0')
    {
        str[i] = '#';
        str2[i] = '#';
        i++;
        str[i] = *src;
        str2[i] = *src;
        i++;
        src++;
    }
    str[i] = '#';
    str2[i] = '#';
    i++;
    str[i] = '\0';
    str2[i] = '\0';

    int len = i;
    int mx=0,id;
    int p[len];
    for(i=1; i<len; ++i)
    {
        if(mx > i)
        {
            p[i] = min(p[2*id-i], p[id]+id-i);
        }
        else
        {
            p[i] = 1;
        }
        while(str[i+p[i]] == str[i-p[i]])
        {
            p[i]++;
        }
        if(p[i]+i > mx)
        {
            mx = p[i]+i;
            id = i;
        }
    }

    for(i=1; i<len; ++i)
    {
        if(str[i] == '#')   //以#為中心的迴文子串
        {
            if(p[i] >= 3)
            {
                for(int j= (i-p[i]+1) ; j<(i+p[i]); ++j)
                {
                    str2[j] = '#';
                }
            }
        }
        else                //以字母為中心的迴文子串
        {
            if(p[i]>=4 && str[i]==str[i-2])
            {
                for(int j= (i-p[i]+1) ; j<(i+p[i]); ++j)
                {
                    str2[j] = '#';
                }
            }
        }
    }

    char *dest = new char[strlen(src)+1];
    char *temp = dest;
    for(i=1; i<len; ++i)
    {
        if(str2[i] != '#')
        {
            *temp++ = str2[i];
        }
    }
    *temp = '\0';
    delete[] str;
    delete[] str2;
 return dest;}int main(){ cout<<"please input a string:"<<endl; char *s=new char; cin>>s; cout<<Manacher(s)<<endl; return 0;}