在字符串处理领域,“求解无重复字符的最长子串长度”是一个经典问题。在Java中,借助“滑动窗口 + 哈希表”的组合能够高效解决该问题。下面将从核心思路、步骤解析到实例演示,全面梳理这一方法,助力快速理解与记忆。
一、核心逻辑:滑动窗口控范围,哈希表记位置
解决该问题的关键在于,利用滑动窗口锁定当前无重复的子串范围,同时通过哈希表记录字符的最新位置,以此快速判断是否存在重复。
- 滑动窗口:由左指针(left)和右指针(right)来界定,区间
[left, right]始终保持不存在重复字符。 - 哈希表:用于存储字符及其最后出现的索引,可快速检测新字符在当前窗口内是否重复,还能确定左指针的移动位置。
二、步骤拆解:从初始化到结果输出
- 初始化参数
- 左指针
left = 0:用于标记当前窗口的起始位置。 - 最大长度
maxLen = 0:记录遍历过程中出现的最长无重复子串长度。 - 哈希表
map:键为字符,值为该字符最后出现的索引(初始时为空)。
- 左指针
- 右指针遍历字符串
右指针从0开始逐步向右移动,每一步都对当前字符
s[right]进行如下处理:- 检测重复并调整左指针:若当前字符
c存在于哈希表中,且其索引≥left(表明在当前窗口内重复),则将左指针移至该索引 + 1(保证窗口内不再包含重复字符)。 - 更新哈希表:将当前字符
c及其索引right存入哈希表,覆盖旧值(始终保持字符的最新位置)。 - 计算并更新最大长度:当前窗口长度为
right - left + 1,将其与maxLen比较,取较大值更新maxLen。
- 检测重复并调整左指针:若当前字符
- 返回结果
遍历结束后,
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)时间复杂度内解决该问题,既高效又易于理解。