繁体   English   中英

最大长度的字符串前缀同构

[英]strings prefix isomorphism with max length

字符串s1和s2是同构的意思-如果将两个字符串做成环,则两个环是相同的。 示例:“ abcd”和“ cdab”是同构的“ abcd”和“ dcba”不是同构的“ cdab”和“ abdc”也不是同构的。

现在您有两个字符串,输出最大长度,使两个字符串的前缀同构。

示例:“ abcdx”和“ cdabz”的最大长度为4。

时间复杂度越低越好。

PS:两个字符串的长度相同

这是一个错误的解决方案,但通过了所有测试

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <stack>
#include <string>
#include <algorithm>
#define MAXN 2000001
#define MOD 100000007
using namespace std;
char str1[MAXN],str2[MAXN];
int next1[MAXN],next2[MAXN],n;
int p[27][26],ct=0;
void getnext(char *s1,char *s2,int* next){
    next[0]=0;
    int pos=2,cnd=0;
    while(pos<n){
        if(s1[pos-1]==s2[cnd])
        {++cnd;next[pos]=cnd;++pos;}
        else if(cnd>0)cnd=next[cnd];
        else {next[pos]=0;++pos;} 
    }
}
void getpri(){
    int cnt=0;
    for(int i=2;cnt<26;i++){
        bool flag=true;
        for(int j=2;j*j<=i;j++)if(i%j==0){flag=false;break;}
        if(flag)p[cnt][ct++]=i;
        if(ct==26)++cnt,ct=0;
    }
}
string s1,s2,str;
bool check(int p){
    str=string(s1.substr(0,p)+s1.substr(0,p));
    int res=str.find(s2.substr(0,p));
    if(res!=-1)return true;
    return false;
}
stack<int>stk;
int main()
{
    freopen("beyond.in","r",stdin);
    freopen("beyond.out","w",stdout);
    getpri();
    scanf("%d\n%s\n%s",&n,str1,str2);
    s1=str1;s2=str2;
    getnext(str1,str2,next1);
    getnext(str2,str1,next2);
    int ans=0;
    long long h1=1,h2=1;
    for(int i=0;i<n;i++){
        if(i>0){
            h1=(h1*p[str1[i-1]-'a'][str1[i]-'a'])%MOD;
            h2=(h2*p[str2[i-1]-'a'][str2[i]-'a'])%MOD;
        }
        if(next1[i+1]+next2[i+1]>=i&&
        h1*p[str1[i]-'a'][str1[0]-'a']==
        h2*p[str2[i]-'a'][str2[0]-'a'])stk.push(i+1);
    }
    while(!stk.empty()){
        if(check(stk.top())){ans=stk.top();break;}
        stk.pop();
    }
    printf("%d\n",ans);
    return 0;
}

PS:可能没有针对该问题的O(n)解,仅当字符串之一为其最小表示形式时,O(n)解才存在。

我认为您可以使用以下方法解决此问题:-

1. Find longest prefix for each substring string1[0 to i] which are also suffix for substring string2[0 to i] and visa versa.Lets call them lps1[i] & lps2[i].
2. if lps1[i] + lps2[i] == i+1 then prefix upto i is isomorphic

example :-

string1 = "abcdx" 
string2 = "cdabz"

lps1[0] = 0
lps2[0] = 0

lps1[1] = 0
lps2[1] = 0

lps1[2] = 1
lps2[2] = 1

lps1[3] = 2
lps2[3] = 2

lps1[4] = 0
lps2[4] = 0

lps1[3] + lps2[3] = 4 = 3+1 hence the largest prefix isomorphic is of length 3+1 = 4

现在的主要问题是如何有效地查找lps?

KMP使用类似的算法在O(|S|)构建表。 检查零件表构建算法,它基本上是用自身构造字符串的lps,但是您可以替换

if W[pos - 1] = W[cnd] 

通过:-

if string1[ pos-1 ] = string2[cnd]  

with some corner checks like cnd < string2.length

时间复杂度:-

Build LPS arrays : O(|S1|+|S2|)

check isomorphic prefix : O(min(|S1|,|S2|)

这是c ++的实现:

#include<cstdio>
#include<cstring>



void ComputeLPS(char* str1,char* str2,int n,int LPS[]) {
  LPS[0] = 0;
  int len = 0,i=1;
  while(i<n){
    if(str2[len]==str1[i]) {
      len++;
      LPS[i] = len;
      i++;
    }
    else {

      if(len!=0) {
    len = LPS[len-1];
      }
      else {
    LPS[i] = 0;
    i++;
      }
    }

  }



}


int isomorphic_prefix(char* str1,char* str2) {

  int n = strlen(str1);
  int lps1[n];
  int lps2[n];

  ComputeLPS(str1,str2,n,lps1);
  ComputeLPS(str2,str1,n,lps2);
  int max = 0;

  for(int i = 0;i < n;i++) {

    int k = lps1[i]+lps2[i];

    if(k==i)
      max = i+1;
  }

  return max;

}



int main() {

  char str1[100];
  char str2[100];

  gets(str1);
  gets(str2);

  printf("max isomorphic prefix : %d",isomorphic_prefix(str1,str2));

  return 0;
}

我对这个问题进行了很多思考,而我得到的是这个问题比我们想象的要简单。 据我,你可以通过保持联系解决这个问题(a,b)这表明字符ab在圆形排列。 如果string1string2的所有链接都相同,则意味着它们是相同的循环排列。 这里的技巧是为字符串1提供一个链接(a,b) +1值,为字符串2提供-1值,因此,如果所有链接相同,则所有对(a,b)计数都为零。 这可以通过对arr[26][26] for all alphabet pairs使用对计数arr[26][26] for all alphabet pairs ,其中arr[a][b]表示两个置换之差的净链接数(a,b)

证明圆形排列可以完全由一组链接表示:

考虑一个循环排列:

X0-> X1-> X2-> X3-> X0

链接集中的表示形式 (x0,x1),(x1,x2),(x2,x3),(x3,x0)

声称这组链接始终仅代表上述排列。

我们将通过矛盾证明这一点。 假设存在可以由同一组链接表示的不同循环置换。 然后,可以通过交换两个字符来形成不同的循环排列。

我们交换x1和x3然后得到置换:

x0->x3->x2->x1->x0

**set of links :-** (x0,x3),(x3,x2),(x2,x1),(x1,x0)

There are two possibilities :-

1. x1 == x3 then new permutation is same as old so there is contradiction here.
2. x1 != x3 then (x0,x3) != (x0,x1) , (x3,x0) != (x1,x0) hence again there is contradiction.


This result can be extended to multiple swaps.

因此,通过矛盾证明了一组链接仅代表一个圆形排列。

使用此结果,我编写了以下c ++实现:

#include<cstdio>
#include<cstring>

inline int getval(char ch) {

 return ch-'a'; 
}



int isomorphic_prefix(char* str1,char* str2) {

 int edges[26][26] = {0};
 int n = strlen(str1);
 int isoprefix = 0;
 int simedges = 676;
 int first1 = getval(str1[0]);
 int first2 = getval(str2[0]);

 for(int i=0;i<n;i++) {


    int prev1,prev2;
    if(i>0) {
        prev1 = getval(str1[i-1]);
        prev2 = getval(str2[i-1]);
    }


    int curr1 = getval(str1[i]);
    int curr2 = getval(str2[i]);

    if(i > 0) {
        if(edges[prev1][first1] == 1)
            simedges++;
        else if(edges[prev1][first1] == 0)
            simedges--;
        edges[prev1][first1]--;
        if(edges[prev2][first2] == -1)
            simedges++;
        else if(edges[prev2][first2] == 0)
            simedges--;
        edges[prev2][first2]++;
        if(edges[prev1][curr1] == 0)
            simedges--;
        else if(edges[prev1][curr1] == -1)
            simedges++;
        edges[prev1][curr1]++;
        if(edges[prev2][curr2] == 0)
            simedges--;
        else if(edges[prev2][curr2] == 1)
            simedges++;
        edges[prev2][curr2]--;

    }

    if(edges[curr1][first1]==0)
        simedges--;
    else if(edges[curr1][first1] == -1)
            simedges++;
    edges[curr1][first1]++;

    if(edges[curr2][first2]==0)
        simedges--;
    else if(edges[curr2][first2] == 1)
            simedges++;
    edges[curr2][first2]--;

    if(simedges == 676)
        isoprefix = i+1;
 }

 return isoprefix;

}




int main() {
    char str1[100];
    char str2[100];
    gets(str1);
    gets(str2);
    printf("%d",isomorphic_prefix(str1,str2));
    return 0;   
}

时间复杂度:-

如您在实现中所看到的,它是O(N)的单循环,内部具有常量计算,因此它是O(N)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM