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");
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41890797/article/details/84992090