LeetCode 无重复字符的最长子串

题目

题意

给出一串字符,找出其中没有重复字符的最长子串

例如:

给出 abcabcbb,其无重复字符的最长子串为 abc,所以输出为 3

给出 abba,其无重复字符的最长子串为 ab 或 ba,所以输出为 2

解决方法

以下将 无重复字符的最长子串 简称为 最长子串

首先想到的解法就是暴力遍历整个字符串,查找最长子串, 伪代码:

n 为字符串长度,ans 为最长子串的长度

for i = 0; i < n; i++ //子串的起始索引

for j = i + 1; j < n; j++ //子串的尾部索引

for k = i; k < j; k++ //在长度为 [i, j) 的子串内检查

if unique ans = max(ans, j – i) //如果没有重复,更新ans

可见暴力算法的时间复杂度为 O(n^3),很容易就超时,因此需要优化算法。

暴力法中,需要不断的重复检查索引在 [i, j) 的子串内是否存在重复字符,而实际上如果在 [i, j-1) 索引内的子串没有出现重复字符,我们只需要检查 j 处的字符是否存在于之前的子串(即 [i, j-1) 子串)内就可以了。

检查一个元素是否存在于一组元素内,我们可以利用集合的性质——集合中的每个元素只能出现一次,使用 Set 来实现,即 Set.isContain(element),从而使时间复杂度降为 O(1)。

此处的集合即本题所涉及到的 “滑动窗口”,我们要维护这个窗口,使其内部没有重复字符。

在这个维护的过程中得到的所有无重复子串中最长的,就是本题的答案,因此,集合内的元素只要加入了新元素,我们就需要与当前的结果 ans 比较大小,取最大值。

伪代码:

S 为字符串,set 为子串字符集合,n 为字符串长度,ans 为最长子串的长度

i = j = 0

while i 和 j < n

if !set.contains(S[j])

set.add(S[j]), j++, ans = max(ans, j – i) //将新元素加入集合,尾部索引 j 向后移,更新 ans

else //集合中有重复元素

set.delete(S[i]), i++ //如果出现了重复字符,则将起始索引 i 一步步向前移,直到重复元素被删除

上述解法还有优化的空间,可以看到如果集合中出现了重复元素后,起始索引是一个一个向前移动的,我们还可以将起始索引 i 一步到位,直接跳到 j-1 的位置,即跳过一个字符窗口,而不是一个字符。

也就是说,如果在 [i, j) 内发现了重复字符(设重复字符的索引为 j‘),我们不需要一步步增加 i,而是跳过 [i, j’) 这个区间,将 i 的值变为 j’ + 1。

我们可以通过映射字符和索引来存储出现过的字符及其索引。

最终代码 (C#):

public class Solution {
    public int LengthOfLongestSubstring(string s) {
        int i = 0, ans = 0, n = s.Length;
            int[] dic = new int[128];
            for (int j = 0; j < n; j++) {
                i = Math.Max(i, dic[s[j]]);
                ans = Math.Max(ans, j - i + 1);
                dic[s[j]] = j + 1;
            }
            return ans;
    }
}

在更新 i (起始索引)的值时,取最大值的意义在于防止起始索引 i 退回到重复的字符索引之前,例如:

如果 i = dic[s[j]] 而不是 i = Max(i, dic[s[j]])。

对于字符串 abba,j = 2 时(第二个 b 处),i = 2 (dic[b] = j + 1 = 1 +1 = 2,),到 j = 3 时,i 的值会回退到 1( i = dic[a],此时的 dic[a] = 1),导致 ans = Max(2, j – i + 1 = 3 – 1 + 1 = 3)。

因为本题的输入只包括字符,所以使用了 128 长度的数组作为映射——字母的ASCII码决定了其在数组中的位置,数组的值为索引,在 C# 中可以使用 Dictionary<char, int>,Python 中可以使用字典 dic = dict({}),C++中可以使用Map<char, int>。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据