请从字符串中找出一个最长的不包含重复字符的连续子字符串,计算该最长连续子字符串长度。假设字符串只包含'a'~'z'的字符。例如在字符串"arabcacfr"中,最长连续子字符串为"acfr",长度为4。
解题思路
这是一道基础的动态规划题,首先应该能想到用暴力法解决,然后再考虑是否能用动态规划来优化。
- 暴力法(复杂度较高O(n^3))
- 动态规划(从左到右,循环计算,降低复杂度)
上代码(C++香)
动态规划法
状态转移方程比较复杂,首先用(f(i))来表示以第i个字符结尾的不包含重复字符的子字符串的最长长度。初始化(f(0) = 1)。
- 如果第i个字符之前没出现过,那么(f(i) = f(i - 1)+1)
- 如果第i个字符之前出现过,求出上次最近出现的位置k,并求出距离(d=i-k):
- 如果(d<=f(i-1)),说明上次出现在(f(i-1))对应的最长子字符串中,此时(f(i)=d)
- 如果(d>f(i-1)),说明上次出现在(f(i-1))对应的最长子字符串外,此时可令(f(i)=f(i-1)+1)
// 动态规划法
int longestSubstringWithOutDuplication(string str){
int length = str.length();
int states[length];
// 初始化第一个数
states[0] = 1;
for(int i = 1; i < length; i++){
// 找出上次最后出现str[i]的位置
int k = -1;
for(int j = 0; j < i; j++){
if(str[j] == str[i])
k = j;
}
// 如果str[i]之前没出现过
if(k == -1)
states[i] = states[i - 1] + 1;
// 如果str[i]之前出现过
// 获得出现距离d
if(k != -1){
int d = i - k;
if(d <= states[i - 1])
states[i] = d;
else
states[i] = states[i - 1] + 1;
}
}
int maxN = -1;
for(int i = 0; i < length; i++){
if(states[i] > maxN)
maxN = states[i];
cout<<states[i]<<" ";
}
cout<<endl;
return maxN;
}
int main(int argc, char* argv[])
{
cout<<longestSubstringWithOutDuplication("arabcacfr");
return 0;
}