[英]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)
这表明字符a
先b
在圆形排列。 如果string1
和string2
的所有链接都相同,则意味着它们是相同的循环排列。 这里的技巧是为字符串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.