字符串s1和s2是同构的意思 - 如果我们将两个弦组成环,则两个环是相同的。 示例:“abcd”和“cdab”是同构的 “abcd”和“dcba”不是isomrphic “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)解决方案仅在其中一个字符串是最小表示时才存在。
答案 0 :(得分:1)
我认为您可以使用以下方法解决此问题: -
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 for string,但你可以替换
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;
}
答案 1 :(得分:0)
我在这个问题上考虑了很多,我得到的是这个问题比我们想象的要简单。根据我的说法,您可以通过在循环排列中保留(a,b)
建议链接a
之前的b
链接来解决此问题。如果string1
和string2
的所有链接相同,则表示它们是相同的循环排列。这里的诀窍是为string1提供链接(a,b)
+1 ,为string2提供 -1 ,因此如果所有链接都相同则所有对{{1}将没有计数。这可以通过使用对(a,b)
来实现,其中arr[26][26] for all alphabet pairs
表示网络链接的数量arr[a][b]
存在两种排列的差异。
证明循环排列可以完全用链接集来表示: -
考虑循环排列: -
X0-&GT; X1-&GT; X2-&GT; X3-&GT; X0
在链接集中的表示形式: - (a,b)
声称这组链接始终只代表上述排列。
我们将通过矛盾来证明这一点。让我们假设有一个不同的循环排列,可以用同一组链接表示。然后可以通过交换两个字符形成不同的圆形排列。
我们交换x1和x3然后我们得到排列: -
(x0,x1),(x1,x2),(x2,x3),(x3,x0)
因此,矛盾证明了一组链接只代表一个循环排列。
使用此结果我编写了以下c ++实现: -
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.
时间复杂度: -
正如您在实现中所看到的那样,它是一个 O(N)的单循环,内部进行常数计算,因此它是 O(N)。