Featured image of post Longest Substring Without Repeating Characters

Longest Substring Without Repeating Characters

3. 无重复字符的最长子串

算法

  1. 维护一个滑动窗口:
    • 滑动窗口用两个指针表示,j 为窗口左端,i 为窗口右端
    • 窗口内的子串为 [j, i],保证该窗口内没有重复字符
  2. 使用哈希表记录字符出现的次数:
    • 哈希表 hashkey 为字符,value 为该字符在窗口中的出现次数
  3. 移动窗口右端:
    • 遍历字符串,右端指针 i 每次右移一格,将字符加入窗口并更新哈希表
  4. 处理重复字符:
    • 如果窗口中出现重复字符(即当前字符的出现次数大于 1),移动左端指针 j,并在哈希表中移除字符,直到窗口内没有重复字符。
  5. 更新结果:
    • 每次移动窗口时,计算当前窗口的长度 (i - j + 1),并更新结果 res

复杂度分析

时间复杂度

每个字符至多被访问两次(右指针扩展时访问一次,左指针收缩时访问一次),时间复杂度为 O(n)

空间复杂度

使用哈希表存储字符出现次数,空间复杂度为 O(k),其中 k 为字符集大小

C++ 代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution
{
public:
    int lengthOfLongestSubstring(string s)
    {
        std::unordered_map<char, int> hash; // 记录字符出现次数
        int res = 0; // 最长子串长度

        for (int i = 0, j = 0; i < s.size(); ++ i)
        {
            ++hash[s[i]]; // 将字符加入窗口

            // 如果出现重复字符,移动左指针 j
            while (hash[s[i]] > 1)
            {
                -- hash[s[j]];
                ++ j;
            }

            // 更新最长子串长度
            res = std::max(res, i - j + 1);
        }

        return res;
    }
};

Python 代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Solution:
  def lengthOfLongestSubstring(self, s: str) -> int:
    res = 0
    freq = {}
    j = 0
    for i, ch in enumerate(s):
      if ch not in freq:
        freq[ch] = 0
      freq[ch] += 1
      while freq[ch] > 1:
        freq[s[j]] -= 1
        j += 1
      res = max(res, i - j + 1)
    return res

Go 代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func lengthOfLongestSubstring(s string) int {
  freq := make(map[byte]int)
  res, j := 0, 0
  for i := 0; i < len(s); i ++ {
    freq[s[i]] ++
    for freq[s[i]] > 1 {
      freq[s[j]] --
      j ++
    }
    res = max(res, i - j + 1)
  }
  return res
}

Javascript

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function (s) {
  let res = 0;
  let freq = new Map();
  for (let i = 0, j = 0; i < s.length; i++) {
    freq.set(s[i], (freq.get(s[i]) || 0) + 1);
    while (freq.get(s[i]) > 1) {
      freq.set(s[j], freq.get(s[j]) - 1);
      j++;
    }
    res = Math.max(res, i - j + 1);
  }
  return res;
};
Built with Hugo
Theme Stack designed by Jimmy