0%

最长不含重复字符的子字符串


题目:

题解:

1、滑动窗口 + 哈希表

  • 解题思路:

    • 滑动窗口,用set维护一个不重复的窗口,如果已经包含该字符,将该字符相等的字符之前的以及此字符元素全部移除,然后记录set的大小最大的就是最长不含重复字符的子字符串数。
  • 复杂度分析:

    • 时间复杂度O(N):其中 N 是字符串的长度。
    • 空间复杂度O(∣Σ∣):,其中 Σ 表示字符集(即字符串中可以出现的字符),∣Σ∣ 表示字符集的大小。在本题中没有明确说明字符集,因此可以默认为所有 ASCII 码在 [0, 128)内的字符,即 ∣Σ∣=128。我们需要用到哈希集合来存储出现过的字符,而字符最多有 ∣Σ∣ 个,因此空间复杂度为 O(∣Σ∣)。
  • 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // 滑动窗口 + 哈希表
    class Solution {
    public int lengthOfLongestSubstring(String s) {
    // 滑动窗口,用set维护一个不重复的窗口
    HashSet<Character> set = new HashSet<>();
    int res = 0;
    int l = 0;
    for (int i = 0; i < s.length(); i++) {
    char c = s.charAt(i);
    // 如果已经包含c,将与c相等的字符之前的元素以及此字符元素全部移除
    while(set.contains(c)) {
    set.remove(s.charAt(l++));
    }
    set.add(c);
    // 或者这样写 res = Math.max(res,set.size());
    res = Math.max(res,i - l + 1);

    }
    return res;
    }
    }

2、动态规划

总体基本思路:

2.1 动态规划 + 哈希表

  • 解题思路:

    • 哈希表统计: 遍历字符串 s 时,使用哈希表(记为 dic )统计 各字符最后一次出现的索引位置 。
    • 左边界 i 获取方式: 遍历到 s[j] 时,可通过访问哈希表 dic[s[j]] 获取最近的相同字符的索引 i 。
  • 复杂度分析:

    • 时间复杂度 O(N) : 其中 N 为字符串长度,动态规划需遍历计算 dp 列表。
    • 空间复杂度O(∣Σ∣):,其中 Σ 表示字符集(即字符串中可以出现的字符),∣Σ∣ 表示字符集的大小。在本题中没有明确说明字符集,因此可以默认为所有 ASCII 码在 [0, 128)内的字符,即 ∣Σ∣=128。我们需要用到哈希集合来存储出现过的字符,而字符最多有 ∣Σ∣ 个,因此空间复杂度为 O(∣Σ∣)。
  • 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 动态规划 + 哈希表
    class Solution2 {
    public int lengthOfLongestSubstring(String s) {
    // 定义map集合,用来存放s中字符的位置对应的索引
    Map<Character, Integer> map = new HashMap<>();
    // tmp是dp
    int res = 0,tmp = 0;
    for (int j = 0; j < s.length(); j++) {
    int i = map.getOrDefault(s.charAt(j),-1);
    map.put(s.charAt(j),j);
    tmp = tmp < j - i ? tmp + 1 : j - i;
    res = Math.max(res,tmp);
    }
    return res;
    }
    }

2.2 双指针 + 哈希表

  • 解题思路:

  • 复杂度分析:

    • 时间复杂度 O(N) : 其中 N 为字符串长度,动态规划需遍历计算 dp 列表。
    • 空间复杂度O(∣Σ∣):,其中 Σ 表示字符集(即字符串中可以出现的字符),∣Σ∣ 表示字符集的大小。在本题中没有明确说明字符集,因此可以默认为所有 ASCII 码在 [0, 128)内的字符,即 ∣Σ∣=128。我们需要用到哈希集合来存储出现过的字符,而字符最多有 ∣Σ∣ 个,因此空间复杂度为 O(∣Σ∣)。
  • 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // 双指针 + 哈希表
    class Solution3 {
    public int lengthOfLongestSubstring(String s) {
    // 定义map集合,用来存放s中字符的位置对应的索引
    Map<Character, Integer> map = new HashMap<>();
    // i 是左指针,j 是右指针
    int res = 0, i = -1;
    for (int j = 0; j < s.length(); j++) {
    // 如果map中已有目前右指针指向的key,
    // 左指针取(已有key的value和目前左指针)的最大值
    // ,因为如果已有key的value在左指针的左边,说明已经有重复的了,移过去再算j - i 就不对了
    if (map.containsKey(s.charAt(j))) {
    i = Math.max(i,map.get(s.charAt(j)));
    }
    map.put(s.charAt(j),j);
    res = Math.max(res,j - i);
    }
    return res;
    }
    }

2.3 可以以此为例子,做解析: