對于一個字符串,請設計一個高效算法,找到字符串的最長無重復字符的子串長度。
窮舉肯定是不行的,這個問題要用到類似于動態規劃的算法:
已知字符串A,設定數組len,另len[i]表示以元素A[i]結尾的,最長的無重復子串。只要求出來len數組中的最大值,即為問題的解。
目前的問題是,已知len[i-1],如何求len[i]?
我們當前處理A[i],已知len[i-1]==5,就可以知道以A[i-1]做結尾的最大無重復子串的長度是5,就可以找到該子串的起始位置p.
- 因為A[i]=='C',如果發現從A[p..i-1]內沒有出現‘C’,就可以把新成員C納入到該子串中。所以以A[i]為結尾的最大無重復子串是A[p..i].
-
如果發現從A[p..i-1]內出現‘C’,那么以A[i]為結尾的最大無重復子串,只能是A[q+1..i].
為了提高搜索某字符在字符串中上一次出現的位置,我們使用一個哈希表來存儲。該表初始化所有元素為-1,提高通用性。
int longestSubstring(string A, int n) {
//哈希表:每個元素上次出現的位置
int pos[256];
for(int i=0;i<256;++i)
pos[i]=-1;//初始-1可以統一化使用
//以i為結尾的最大無重復串長度
int *len=new int[n]();
//初始化0號字符的情況
len[0]=1;
pos[A[0]]=0;
for(int i=1;i<n;++i){
//為了處理方便,q的定義與圖示
int q=pos[A[i]]+1;
int p=i-len[i-1];
len[i]=q<p?i-p+1:i-q+1;
pos[A[i]]=i;
}
//找出len數組中最大值
int max=0;
for(int i=0;i<n;++i){
if(len[i]>max)
max=len[i];
}
delete[] len;
return max;
}