Java 实现最长无重复子串长度的求解

84 阅读3分钟

在字符串处理领域,“求解无重复字符的最长子串长度”是一个经典问题。在Java中,借助“滑动窗口 + 哈希表”的组合能够高效解决该问题。下面将从核心思路、步骤解析到实例演示,全面梳理这一方法,助力快速理解与记忆。

一、核心逻辑:滑动窗口控范围,哈希表记位置

解决该问题的关键在于,利用滑动窗口锁定当前无重复的子串范围,同时通过哈希表记录字符的最新位置,以此快速判断是否存在重复。

  • 滑动窗口:由左指针(left)和右指针(right)来界定,区间 [left, right] 始终保持不存在重复字符。
  • 哈希表:用于存储字符及其最后出现的索引,可快速检测新字符在当前窗口内是否重复,还能确定左指针的移动位置。

二、步骤拆解:从初始化到结果输出

  1. 初始化参数
    • 左指针 left = 0:用于标记当前窗口的起始位置。
    • 最大长度 maxLen = 0:记录遍历过程中出现的最长无重复子串长度。
    • 哈希表 map:键为字符,值为该字符最后出现的索引(初始时为空)。
  2. 右指针遍历字符串 右指针从0开始逐步向右移动,每一步都对当前字符 s[right] 进行如下处理:
    • 检测重复并调整左指针:若当前字符 c 存在于哈希表中,且其索引≥left(表明在当前窗口内重复),则将左指针移至该索引 + 1(保证窗口内不再包含重复字符)。
    • 更新哈希表:将当前字符 c 及其索引 right 存入哈希表,覆盖旧值(始终保持字符的最新位置)。
    • 计算并更新最大长度:当前窗口长度为 right - left + 1,将其与 maxLen 比较,取较大值更新 maxLen
  3. 返回结果 遍历结束后,maxLen 就是字符串中无重复字符的最长子串长度。

三、代码实现:简洁骨架与关键逻辑

public int lengthOfLongestSubstring(String s) {
    Map<Character, Integer> map = new HashMap<>();
    int maxLen = 0, left = 0;
    for (int right = 0; right < s.length(); right++) {
        char c = s.charAt(right);
        // 若字符重复且在当前窗口内,移动左指针
        if (map.containsKey(c) && map.get(c) >= left) {
            left = map.get(c) + 1;
        }
        // 更新字符最新位置
        map.put(c, right);
        // 计算当前窗口长度并更新最大值
        maxLen = Math.max(maxLen, right - left + 1);
    }
    return maxLen;
}

四、实例演示:直观理解窗口移动过程

以字符串 abcabcbb 为例,逐步观察窗口的调整过程:

  • 右指针 = 0(字符 'a'):窗口为 [0,0]maxLen = 1,哈希表记录为 {'a':0}
  • 右指针 = 1(字符 'b'):窗口为 [0,1]maxLen = 2,哈希表记录为 {'a':0, 'b':1}
  • 右指针 = 2(字符 'c'):窗口为 [0,2]maxLen = 3,哈希表记录为 {'a':0, 'b':1, 'c':2}
  • 右指针 = 3(字符 'a'):'a' 已在哈希表中,且索引0≥left=0(处于当前窗口内),所以left移至1。窗口变为 [1,3],长度为3,maxLen 保持3,哈希表更新为 {'a':3}

后续右指针继续移动,左指针会根据需要进行调整,最终得出最长子串长度为3。

五、记忆口诀:快速掌握核心

左窗右滑,哈希记位; 遇重复,左移超旧位; 每步算长,更新最大。

通过“右指针扩张窗口、左指针收缩去重、哈希表追踪位置、实时更新最大长度”这四个步骤,能够在O(n)时间复杂度内解决该问题,既高效又易于理解。