10.滑动窗口解决:无重复字符的最长子串 | LeetCode 3 Java 题解
目录
一、题目解析
示例 1:
示例 2:
示例 3:
二、算法原理
解法一:暴力枚举 + 哈希表(O(n²))
解法二:滑动窗口(推荐!O(n))
滑动窗口的核心步骤:
三、编写代码(Java)
for循环写法(推荐!!!)
while循环写法
四、总结
OJ链接:无重复字符的最长子串
哈喽大家好!今天咱们来啃一道经典的算法题——无重复字符的最长子串。这道题在 LeetCode 上是第 3 题,难度中等,但绝对是必练的滑动窗口入门题!
一、题目解析
先看题目描述:
给定一个字符串
s,请你找出其中不含有重复字符的最长子串的长度。
注意关键词:子串(必须是连续的!)和无重复字符。
示例 1:
输入:
s = "abcabcbb"输出:3
解释:因为无重复字符的最长子串是
"abc",所以长度为 3。
示例 2:
输入:
s = "bbbbb"输出:1
解释:因为无重复字符的最长子串是
"b",所以长度为 1。
示例 3:
输入:
s = "pwwkew"输出:3
解释:因为无重复字符的最长子串是
"wke",所以长度为 3。(注意"pwke"是子序列,不是子串!)
📌小贴士:子串 vs 子数组 → 都是连续的一段!别被“子序列”带偏了!
二、算法原理
这道题有几种解法,我们重点讲两种:
解法一:暴力枚举 + 哈希表(O(n²))
枚举所有子串,用哈希表判断是否有重复字符。
时间复杂度高,不推荐,但可以作为理解题意的起点。
解法二:滑动窗口(推荐!O(n))
利用“窗口”思想,维护一个无重复字符的连续区间。
用两个指针
left和right表示窗口左右边界。用一个数组(或哈希表)记录每个字符出现的次数。
滑动窗口的核心步骤:
初始化:
left = 0,right = 0进窗口:让
s[right]进入窗口 →hash[s[right]]++判断:如果
hash[s[right]] > 1→ 说明有重复!出窗口:从左边开始删,直到重复字符被移除 →
hash[s[left++]]--更新结果:
ret = Math.max(ret, right - left + 1)移动右指针:
right++
关键点:窗口内始终是无重复字符的!一旦重复,就收缩左边界,直到恢复无重复状态。
三、编写代码(Java)
我整理了两种写法,for循环写法更推荐(结构清晰,易读),也保留了while循环写法,方便你对比学习。
for循环写法(推荐!!!)
class Solution { public int lengthOfLongestSubstring(String ss) { // 先转换为字符数组 char[] s = ss.toCharArray(); // 数组模拟哈希表存储每个字符出现的次数 // 也是滑动窗口需要维护的数据 int hash[] = new int[128]; int n = ss.length(); int len = 0; for(int left = 0, right = 0; right < n; right++) { // 入窗口 hash[s[right]]++; // 判断 while(hash[s[right]] > 1) { // 出窗口 hash[s[left++]]--; } // 更新结果 len = Math.max(len, right - left + 1); } return len; } }while循环写法
class Solution { public int lengthOfLongestSubstring(String ss) { char[] s = ss.toCharArray(); int[] hash = new int[128]; int left = 0, right = 0; int ret = 0; int n = ss.length(); while (right < n) { // 入窗口 hash[s[right]]++; // 判断 while (hash[s[right]] > 1) { // 出窗口 hash[s[left++]]--; } // 更新结果 ret = Math.max(ret, right - left + 1); // 让下一个字符进入窗口 right++; } return ret; } }四、总结
这道题是滑动窗口的经典入门题,核心是:
用双指针维护窗口
用数组/哈希表记录字符频次
遇到重复就收缩左边界
每次更新最大长度
时间复杂度:O(n)
空间复杂度:O(1)(因为字符集固定128)
