【剑指Offer】面试题48:最长不含有重复字符的子字符串

题目:请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。假设字符串中只包含‘a’~‘z’的字符。例如,在字符串“arabcacfr”中,最长的不含重复字符的子字符串是“acfr”,长度为 4。

思路 1:动态规划

这道题很明显是一道动态规划的问题,我们通过举例来分析一下:对于字符串“arabcacfr”,

  1. 以第 0 个字符结尾的(从 0 开始计数)所对应最长的不含重复字符的子字符串的长度为 1,是“a”
  2. “第 1 个字符结尾的所对应最长的不含重复字符的子字符串的长度”=“第 0 个字符结尾的所对应最长的不含重复字符的子字符串的长度”+ 1,等于 2,是“ar”
  3. “第 2 个字符结尾的所对应最长的不含重复字符的子字符串的长度”=“与第 1 个字符结尾的所对应最长的不含重复字符的子字符串中的重复字符的距离”,2 - 0 = 2,是“ra”
  4. “第 3 个字符结尾的所对应最长的不含重复字符的子字符串的长度”=“第 2 个字符结尾的所对应最长的不含重复字符的子字符串的长度”+ 1,等于 3,是“rab”
  5. “第 4 个字符结尾的所对应最长的不含重复字符的子字符串的长度”=“第 3 个字符结尾的所对应最长的不含重复字符的子字符串的长度”+ 1,等于 4,是“rabc”
  6. “第 5 个字符结尾的所对应最长的不含重复字符的子字符串的长度”=“与第 4 个字符结尾的所对应最长的不含重复字符的子字符串中的重复字符的距离”,5 - 2 = 3,是“bca”
  7. “第 6 个字符结尾的所对应最长的不含重复字符的子字符串的长度”=“与第 5 个字符结尾的所对应最长的不含重复字符的子字符串中的重复字符的距离”,6 - 4 = 2,是“ac”
  8. “第 7 个字符结尾的所对应最长的不含重复字符的子字符串的长度”=“第 7 个字符结尾的所对应最长的不含重复字符的子字符串的长度”+ 1,等于 3,是“acf”
  9. “第 8 个字符结尾的所对应最长的不含重复字符的子字符串的长度”=“第 7 个字符结尾的所对应最长的不含重复字符的子字符串的长度”+ 1,等于 4,是“acfr”

从以上的分析,我们可以观察到:第 i 个字符结尾的所对应最长的不含重复字符的子字符串的长度只与第 i - 1 个字符结尾的所对应最长的不含重复字符的子字符串的长度有关,而且子问题有重叠部分,状态转移方程如下:

$$
f(i) =
\begin{cases}
f(i-1)+1, & 第 i 个字符结尾的不在上一个最长不含重复字符的子字符串中\\
d, & 第 i 个字符结尾的在上一个最长不含重复字符的子字符串中
\end{cases}
$$

其中,f(i) 表示第 i 个字符结尾的所对应最长的不含重复字符的子字符串的长度,d 表示第 i 个字符结尾的与上一个最长不含重复字符的子字符串中的相同字符的距离。

默认使用一个一维数组记录每个字符结尾的子字符串的长度,这里可以优化成只使用一个变量记录最大的长度。