LeetCode——3. 无重复字符的最长子串(Java)
题目
给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
一、滑动窗口+哈希表
时间复杂度O(N);空间复杂度O(N)
- 循环条件:right < s.length(),确保右边界不会超出字符串长度。当前字符:char current = s.charAt(right),获取当前右边界指向的字符。
- 如果当前字符current已经在set中,说明当前窗口内出现了重复字符。此时,需要缩小窗口,通过将左边界left向右移动,并从set中移除left指向的字符。同时,窗口长度temp减1。
- 如果当前字符current不在set中,说明当前窗口内没有重复字符。
将当前字符current添加到set中。
右边界right向右移动,窗口长度temp加1。
更新最长无重复字符子串的长度ans,取ans和temp中的较大值。
class Solution {
public int lengthOfLongestSubstring(String s) {
Set<Character> set=new HashSet<>();
int left=0,temp=0,right=0,ans=0;
while(right<s.length()){
char current=s.charAt(right);
if(set.contains(current)){
set.remove(s.charAt(left));
left++;
temp--;
}else{
set.add(current);
right++;
temp++;
ans=Math.max(ans,temp);
}
}
return ans;
}
}
初始状态:left = 0, right = 0, temp = 0, ans = 0,set = {}
第一步:right = 0,current = ‘a’,set = {‘a’},temp = 1,ans = 1
第二步:right = 1,current = ‘b’,set = {‘a’, ‘b’},temp = 2,ans = 2
第三步:right = 2,current = ‘c’,set = {‘a’, ‘b’, ‘c’},temp = 3,ans = 3
第四步:right = 3,current = ‘a’,set = {‘b’, ‘c’},left = 1,temp = 2
第五步:right = 4,current = ‘b’,set = {‘c’, ‘a’, ‘b’},temp = 3,ans = 3
以此类推,最终ans = 3。
二、滑动窗口+数组
时间复杂度O(N),空间复杂度O(N)
- 当前字符的ASCII值:int index = s.charAt(i),获取当前字符的ASCII值。
- 如果当前字符index之前出现过,last[index]记录的是该字符上次出现的位置加1。
如果last[index]大于当前左边界left,说明当前字符在当前窗口内重复了,需要将左边界移动到last[index],从而跳过重复字符。
如果last[index]小于或等于left,说明该字符上次出现的位置在当前窗口之外,不影响当前窗口,左边界保持不变。 - 计算当前窗口的长度i - left + 1,并更新right为当前窗口长度和right中的较大值。
- 将当前字符的最后出现位置更新为当前索引加1。
class Solution {
public int lengthOfLongestSubstring(String s) {
int[] last=new int[128];
int left=0,right=0;
for(int i=0;i<s.length();i++){
int index=s.charAt(i);
left=Math.max(left,last[index]);
right=Math.max(right,i-left+1);
last[index]=i+1;
}
return right;
}
}
初始状态:left = 0, right = 0,last = {0, 0, …, 0}(128个0)
第一步:i = 0,index = ‘a’,last[‘a’] = 0,left = Math.max(0, 0) = 0,right = Math.max(0, 0 - 0 + 1) = 1,last[‘a’] = 1
第二步:i = 1,index = ‘b’,last[‘b’] = 0,left = Math.max(0, 0) = 0,right = Math.max(1, 1 - 0 + 1) = 2,last[‘b’] = 2
第三步:i = 2,index = ‘c’,last[‘c’] = 0,left = Math.max(0, 0) = 0,right = Math.max(2, 2 - 0 + 1) = 3,last[‘c’] = 3
第四步:i = 3,index = ‘a’,last[‘a’] = 1,left = Math.max(0, 1) = 1,right = Math.max(3, 3 - 1 + 1) = 3,last[‘a’] = 4
第五步:i = 4,index = ‘b’,last[‘b’] = 2,left = Math.max(1, 2) = 2,right = Math.max(3, 4 - 2 + 1) = 3,last[‘b’] = 5
以此类推,最终right = 3。