1. 程式人生 > >A + B for you again(兩個字串拼接--第一個的字尾與第二個字首相等時省略一個)

A + B for you again(兩個字串拼接--第一個的字尾與第二個字首相等時省略一個)

Generally speaking, there are a lot of problems about strings processing. Now you encounter another such problem. If you get two strings, such as “asdf” and “sdfg”, the result of the addition between them is “asdfg”, for “sdf” is the tail substring of “asdf” and the head substring of the “sdfg” . However, the result comes as “asdfghjk”, when you have to add “asdf” and “ghjk” and guarantee the shortest string first, then the minimum lexicographic second, the same rules for other additions.

Input

For each case, there are two strings (the chars selected just form ‘a’ to ‘z’) for you, and each length of theirs won’t exceed 10^5 and won’t be empty.

Output

Print the ultimate string by the book.

Sample Input

asdf sdfg
asdf ghjk

Sample Output

asdfg
asdfghjk

題意:

         給定兩個字串,將兩個字串拼接在一塊,當一個字串的字首與另一個字串的字尾相同時省略一部分,使得拼接後的長度最短,字典序最小。

思路:我用了兩種方法來寫:

          第一種方法:雜湊,從第一個字串的最後一個字元開始,倒著遍歷,求出所有後綴的雜湊值。然後在第二個字串正著遍歷求雜湊值,記錄長的匹配值,然後就可以求出拼接後的字串了。

           第二種方法:KMP,因為是兩個字串相同的字首和字尾,那麼可以將兩個字串拼接,求next陣列即可。切記當求出的next[len]的值大於在前面的字串的長度時,這時結果長度應為第一個字串的長度(eg: aaa     aaaaaa)

以上兩種方法都要求兩遍,s+t    t+s

雜湊程式碼如下:

#include<cstdio>
#include<cstring>
#include<set>
#include<algorithm>
#define N 100010
#define LL unsigned long long
using namespace std;
char ss[N],tt[N];
set<LL>hashmark;//set儲存hash值
int work(char s[],char t[],int l1,int l2,int &b)//s + t
{
    hashmark.clear();
    LL temp=1,sum=0;
    for(int i=l1-1; i>=0; i--)//倒著遍歷s,求s字尾的hash值
    {
        sum=sum+(LL)(s[i]-'a'+1)*temp;
        temp*=31;
        hashmark.insert(sum);
    }
    sum=0;
    int p=0;
    for(int i=0; i<l2; i++) //正著遍歷 t
    {
        sum=sum*31+(LL)(t[i]-'a'+1);
        if(hashmark.count(sum)==1)
            p=i+1;//要最長的匹配長度
    }
    b=p;//在p點不匹配了
    return l1+(l2-b+1);//返回最終字串的長度
}
int main()
{
    while(~scanf("%s%s",ss,tt))
    {
        int l1=strlen(ss);
        int l2=strlen(tt);
        int a,b;
        int n=work(ss,tt,l1,l2,a); // s + t
        int m=work(tt,ss,l2,l1,b); // t + s
        if(n<m)//第一種結果更短
        {
            for(int k=0; k<l1; k++)
                printf("%c",ss[k]);
            for(int k=a; k<l2; k++)
                printf("%c",tt[k]);
        }
        else if(n>m) //第二種結果更短
        {
            for(int k=0; k<l2; k++)
                printf("%c",tt[k]);
            for(int k=b; k<l1; k++)
                printf("%c",ss[k]);
        }
        else  //兩種結果長度相同,求字典序最小的
        {
            if(strcmp(ss,tt)<0)
            {
                for(int k=0; k<l1; k++)
                    printf("%c",ss[k]);
                for(int k=a; k<l2; k++)
                    printf("%c",tt[k]);
            }
            else
            {
                for(int k=0; k<l2; k++)
                    printf("%c",tt[k]);
                for(int k=b; k<l1; k++)
                    printf("%c",ss[k]);
            }
        }
        printf("\n");
    }
}

KMP程式碼如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200010
using namespace std;
char ss[N],tt[N],str[N];
int nextt[N];
int work(int l)//求next陣列
{
    nextt[0]=-1;
    int i=0,k=-1;
    while(i<l)
    {
        if(k<0||str[i]==str[k])
            nextt[++i]=++k;
        else
            k=nextt[k];
    }
    return nextt[l];//返回next[l]的值,即在這點失配
}
int solve(char s[],char t[],int l1,int l2,int &flag)
{
    for(int i=0; i<l2; i++)//把兩個字串和並
        str[i]=t[i];
    int a=l2;
    for(int i=0; i<l1; i++)
        str[a++]=s[i];
    str[a]=0;
    a=work(a);
    if(a>l1)a=l1;//最後長度應小於 l1
    flag=a;//在a點失配
    return l1+(l2-a);//返回長度
}
int main()
{
    while(~scanf("%s%s",ss,tt))
    {
        int l1=strlen(ss);
        int l2=strlen(tt);
        int a,b,n,m;
        n=solve(ss,tt,l1,l2,a);//s+t,即將s放在t後面求next陣列
        m=solve(tt,ss,l2,l1,b);//t+s
        if(n<m)
        {
            for(int k=0; k<l1; k++)
                printf("%c",ss[k]);
            for(int k=a; k<l2; k++)
                printf("%c",tt[k]);
        }
        else if(n>m)
        {
            for(int k=0; k<l2; k++)
                printf("%c",tt[k]);
            for(int k=b; k<l1; k++)
                printf("%c",ss[k]);
        }
        else
        {
            if(strcmp(ss,tt)<0)
            {
                for(int k=0; k<l1; k++)
                    printf("%c",ss[k]);
                for(int k=a; k<l2; k++)
                    printf("%c",tt[k]);
            }
            else
            {
                for(int k=0; k<l2; k++)
                    printf("%c",tt[k]);
                for(int k=b; k<l1; k++)
                    printf("%c",ss[k]);
            }
        }
        printf("\n");
    }
}