1.穷举法,每往后查找一个字符,将其与前面的串比较一遍,不重复将其加到前面的串里,否则从前面串的下一个字符再次进行同样的循环。(这里当该字符与前面串第一个重复时才不浪费时间,否者会多进行很多次无用的比较)
void GEtDIfNUm1(char* str)
{
int maxlen=0;
int begin=0;
int len=strlen(str);
int flag;
if(len==1) //防止一个字符那种情况
{
cout<<str[0]<<endl;
return;
}
for(int i=0;i<len-1;i++)
{
flag=0;
begin=0;
for(int j=i+1;j<len;j++)
{
for(int m=i;m<j;m++)
{
if(str[m]==str[j])
{
if(j-i>maxlen)
{
maxlen=j-i;
begin=i;
}
flag=1;
break;
}
}
if(flag==1)
break;
}
}
for(int i=begin;i<maxlen;i++)
cout<<str[i];
cout<<maxlen<<endl;
}
时间复杂度:O(n^3)
2.hash表去记录重复的字符
int GEtDIfNUm2(char* str)
{
int hash[250];
int len=strlen(str);
int begin=0;
int maxNUm=0;
for(int i=0;i<len-1;i++)
{
memset(hash,0,sizeof(hash));
hash[str[i]]=1;
for(int j=i+1;j<len;j++)
{
if(hash[str[j]]==1)
{
begin=i;
if(j-i>maxNUm)
{
maxNUm=j-i;
break;
}
}
}
}
return maxNUm;
}
时间复杂度:O(n^2)
3.hash表加dp
一.构造first数组和next数组,first数组是指包括当前字符的后面第一次出现重复字符的下标,next数组指和当前字符重复的下一个位置的下标,如果出现同一个字符的多次重复的情况,则每次取它后面距离最近的那个字符的下标。最后就是求所有情况中first[i]-i最大的那个。
int GEtDIfNUm3(char* str)
{
int MAxLEn=0;
int BEgin=0;
int n=strlen(str);
int* first=(int*)malloc(sizeof(int)*(n+1));
int* next=(int*)malloc(sizeof(int)*n);
int hash[256];
first[n]=n;
memset(hash,n,sizeof(hash));
for(int i=n-1;i>=0;i--)
{
next[i]=hash[str[i]];
hash[str[i]]=i;
if(next[i]<first[i+1])
{
first[i]=next[i];
}
else
{
first[i]=first[i+1];
}
}
for(int i=0;i<n;i++)
{
if(first[i]-i>MAxLEn)
{
MAxLEn=first[i]-i;
BEgin=i;
}
}
for(int i=BEgin;i<BEgin+MAxLEn;i++)
{
cout<<str[i];
}
cout<<endl;
return MAxLEn;
}
时间复杂度:O(n)
二.在上面的一点改进,上面更加像从后往前,这里就从前往后了,visit数组保留的是当前字符的下标,后面出现重复的时就会进行比较,如果该重复的字符在目前比较的字符串中间的话,那么就从下一个字符串开始比较,下一个字符串开始的位置就是该重复字符的下一个字符,如果不在中间,就把该字符加到目前字符串中,并把他的下标改为他目前的位置。
int GEtDIfNUm4(char* str)
{
int visit[256];
memset(visit,-1,sizeof(visit));
int n=strlen(str);
int CUrLEn=1;
int BEgin;
int MAxLEn=0;
int lastBEgin=0;
visit[str[0]]=0;
for(int i=1;i<n;i++)
{
if(visit[str[i]]==-1)
{
CUrLEn++;
visit[str[i]]=i;
}
else
{
if(lastBEgin<visit[str[i]]) //这里那些没必要进行的比较删除了,上面穷举这里要从头开始,而这里只是从那个重复的字符后面开始
{
CUrLEn=i-visit[str[i]];
lastBEgin=visit[str[i]]+1;
}
else
{
CUrLEn++;
}
visit[str[i]]=i;
}
if(CUrLEn>MAxLEn)
{
MAxLEn=CUrLEn;
BEgin=lastBEgin;
}
}
for(int i=BEgin;i<BEgin+MAxLEn;i++)
{
cout<<str[i];
}
cout<<endl;
return MAxLEn;
}
时间复杂度:O(n)
4.使用后缀数组,个人觉得这种最好理解(首先要理解后缀数组是啥,前缀数组是啥)
计算每个后缀数组的不重复的前缀数组的长度,然后比较求最长的那个长度就可以了。
int GEtLOngestDiLEn(char* str)
{
int hash[256];
int LEn=0;
memset(hash,0,sizeof(hash));
while(*str&&!hash[*str])
{
LEn++;
hash[*str]=1;
str++;
}
return LEn;
}
int GEtDIfNUm5(char* str)
{
int MAxLEn=0;
int CUrLEn;
int n=strlen(str);
int BEgin;
for(int i=0;i<n;i++)
{
CUrLEn=GEtLOngestDiLEn(&str[i]);
if(CUrLEn>MAxLEn)
{
MAxLEn=CUrLEn;
BEgin=i;
}
}
for(int i=BEgin;i<BEgin+MAxLEn;i++)
{
cout<<str[i];
}
cout<<endl;
return MAxLEn;
}
时间复杂度:O(n^2)
主要借鉴了下面的文章
/*
http://blog.csdn.net/insistgogo/article/details/7830972
http://www.cnblogs.com/luxiaoxun/archive/2012/10/02/2710471.html
*/