/*
每个状态存最长匹配长度,然后多个串匹配过程中取最小的最长匹配长度
和LCS1不同的地方:LCS只要维护住当前匹配长度和最长匹配长度即可,但是多串匹配需要维护的是每个状态结点(即后缀树上)的信息
所以对每个状态存下两个值Max,Min,分别表示该状态对于该串的最长匹配长度,以及所有已经匹配过的串在该状态下的最小的最长匹配长度
在对一个串进行匹配后,在后缀树上自底向上回溯一次,更新Max值
更新完Max后再更新Min
*/
#include<bits/stdc++.h>
using namespace std;
#define maxn 400005
struct SAM{
int last,cnt;
int nxt[maxn][26],len[maxn],link[maxn];
SAM(){last=cnt=1;}
void add(int c){
int p=last,np=last=++cnt;
len[np]=len[p]+1;
for(;p&&!nxt[p][c];p=link[p])
nxt[p][c]=np;
if(!p){link[np]=1;return;}
int q=nxt[p][c];
if(len[q]==len[p]+1){link[np]=q;return;}
int clone=++cnt;
link[clone]=link[q];
len[clone]=len[p]+1;
memcpy(nxt[clone],nxt[q],sizeof nxt[q]);
link[q]=link[np]=clone;
for(;p&&nxt[p][c]==q;p=link[p])
nxt[p][c]=clone;
}
int Min[maxn],Max[maxn],t[maxn],id[maxn];
void sort(){
for(int i=1;i<=cnt;i++)t[len[i]]++;
for(int i=1;i<=cnt;i++)t[i]+=t[i-1];
for(int i=1;i<=cnt;i++)id[t[len[i]]--]=i;
for(int i=1;i<=cnt;i++)Min[i]=len[i];
}
void update(char *s){
memset(Max,0,sizeof Max);
int now=1,cur=0,Len=strlen(s);
for(int i=0;i<Len;i++){
int p=s[i]-'a';
if(nxt[now][p]){
cur++;
now=nxt[now][p];
}else {
while(now && !nxt[now][p])
now=link[now];
if(now){
cur=len[now]+1;
now=nxt[now][p];
}else {
cur=0;now=1;
}
}
Max[now]=max(Max[now],cur);
}
for(int i=cnt;i>=1;i--){
int tmp=id[i];
Max[link[tmp]]=max(Max[link[tmp]],Max[tmp]);
}
for(int i=cnt;i>=1;i--)
Min[i]=min(Min[i],Max[i]);
}
int calc(){
int res=0;
for(int i=1;i<=cnt;i++)res=max(res,Min[i]);
return res;
}
}p;
char s[maxn];
int main(){
cin>>s;
int len=strlen(s);
for(int i=0;i<len;i++)p.add(s[i]-'a');
p.sort();
while(scanf("%s",s)!=EOF)
p.update(s);
cout<<p.calc()<<endl;
}