## **题目** 给定一个字符串,假设该字符串是由 26 个小写英文字母组成,如字符串 "acbccradfr",其最长连续不重复子串的长度为 5,对应的子串是 "cradf"。 ## **思路** 动态规划:按 C 语言习惯,索引从 0 开始。假设映射 `$ f(i) := 以第 i 个字符为结尾的子串的最长连续不重复子串的长度 $`,由此定义得知,如果第 i + 1 个字符到第 i 个字符前还没出现过,那么 `$ f(i + 1) = f(i) + 1 $`。如果第 i + 1 个字符已经出现过,那么又有两种情况:一种是这个字符到它上次出现时的距离```d```(索引之差)小于或等于 ```f(i)```,也就是说该字符上次出现的位置是以第 i 个字符结尾的最长连续子串的一部分,此时`$ f(i + 1) = d $`。如`$ f(2) = 3 $`,要求`$ f(3) $`,观察知第 3 个字符 c 已经在第 1 个位置出现过一次了,因为d = 3 - 1 = 2 < f(2),所以 `$ f(3) = 2 ("bc") $`;另一种情况是 `$ d > f(i) $`时,这意味着该字符上次出现的位置不是以第 i 个字符结尾的最长连续子串的构成部分,所以此时`$ f(i + 1) = f(i) + 1 $`。 ## 代码 ``` C++ #define MAXN 26 int longestSubLength(string &str) { int length = str.length(); if (length == 0) { return 0; } int pos[26]; memset(pos, -1, sizeof(pos)); int curLength = 0; int maxLength = 0; for (int i = 0; i < length; ++i) { int p = pos[str[i] - 'a']; // 没出现过或距离大于f(i) if (p < 0 || i - p > curLength) { ++curLength; } else { // 距离小于或等于f(i),只有这里可能减小最长长度,所以记下之前的最长长度 if (maxLength < curLength) { maxLength = curLength; } curLength = i - p; } } if (maxLength < curLength) { maxLength = curLength; } return maxLength; } ```