今天搬工位了,研二的师兄师姐在这儿坐了半年,现在轮到我么们了。做题先
1、题目描述
2、逻辑分析
题目要求很明确,就是要找出无重复字符的最长。怎么求解呢?题解给出了滑动窗口的算法方案。
3、代码演示
public int lengthOfLongestSubstring(String s) {
// 创建一个HashSet来存储已经出现过的字符,以便快速检查某个字符是否已经出现过
Set<Character> occ = new HashSet<Character>();
// 获取字符串的长度
int n = s.length();
// 初始化右指针rk为-1,表示还未开始寻找子串
// ans存储最长子串的长度,初始化为0
int rk = -1 , ans = 0;
// 遍历字符串的每一个字符
for(int i = 0; i < n; i++){
// 如果i不是第一个字符(即i不等于0),则从HashSet中移除前一个字符,因为当前子串的起始位置已经后移了
if(i != 0){
occ.remove(s.charAt(i - 1));
}
// 使用while循环来扩展当前子串,直到遇到已经出现过的字符或者到达字符串的末尾
// 如果当前字符不在HashSet中,说明可以添加到子串中,并且更新rk
while(rk + 1 < n && !occ.contains(s.charAt(rk + 1))){
occ.add(s.charAt(rk + 1));
rk++;
}
// 更新最长子串的长度,取当前子串长度(rk - i + 1)和之前记录的最长子串长度ans的较大值
ans = Math.max(ans , rk - i + 1);
}
// 返回最长子串的长度
return ans;
}
这段代码使用双指针(一个左指针i和一个右指针rk)和一个HashSet来解决问题。左指针 i 用于遍历字符串的每个字符,右指针 rk 用于扩展当前子串。每次移动左指针时,都会从HashSet中移除前一个字符,以确保当前子串不包含重复字符。然后,使用while循环来扩展当前子串,直到遇到重复字符或到达字符串的末尾。最后,更新最长子串的长度并返回。
我们可以使用字符串 “abcabcbb” 作为例子来详细解释上述代码的执行过程。字符串: “abcabcbb”
初始状态: occ (HashSet): 空集,n (字符串长度): 7,rk (右指针): -1,ans (最长子串长度): 0,i (左指针): 即将开始遍历。
步骤 1
(i = 0, rk = -1, ans = 0): occ.remove(s.charAt(i - 1)): 不执行(因为 i = 0)
while 循环: 将 ‘a’ 添加到 occ,rk 增加到 0
更新 ans: ans = Math.max(ans, rk - i + 1) = Math.max(0, 1) = 1
步骤 2
(i = 1, rk = 0, ans = 1): occ.remove(s.charAt(i - 1)): 移除 ‘a’
while 循环: 将 ‘b’ 添加到 occ, rk 增加到 1
更新 ans: ans = Math.max(ans, rk - i + 1) = Math.max(1, 2) = 2
步骤 3
(i = 2, rk = 1, ans = 2): occ.remove(s.charAt(i - 1)): 移除 ‘b’
while 循环: 将 ‘c’ 添加到 occ, rk 增加到 2
更新 ans: ans = Math.max(ans, rk - i + 1) = Math.max(2, 3) = 3
步骤 4
(i = 3, rk = 2, ans = 3): occ.remove(s.charAt(i - 1)): 移除 ‘c’
while 循环: !occ.contains(s.charAt(rk + 1)): 否(因为 ‘a’ 已经在 occ 中)
不执行添加和增加 rk
更新 ans: 保持为 3
步骤 5
(i = 4, rk = 2, ans = 3): occ.remove(s.charAt(i - 1)): 移除 ‘a’(这是之前 rk 指向的字符)
while 循环: rk + 1 < n: 是(因为 rk = 2), !occ.contains(s.charAt(rk + 1)): 是(因为 ‘b’ 不在 occ 中)
将 ‘b’ 添加到 occ , rk 增加到 3
更新 ans: ans = Math.max(ans, rk - i + 1) = Math.max(3, 2) = 3(长度没有增加)