力扣刷题笔记day2
3. 无重复字符的最长子串
题意
给定一个字符串 s
,请你找出其中不含有重复字符的 最长子串 的长度。
示例
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
分析
首先想到暴力解,利用两层循环,设置一个数组存储出现过的字符,外层循环为起始位,内层循环不断延申,当遇到存在过的字符时,中断内层循环。设置length,内层循环每循环一次,就判断是否有更长的长度,有就更新。
class Solution4 {
public int lengthOfLongestSubstring(String s) {
int length=0;
for (int i = 0; i < s.length(); i++) {
boolean[] num=new boolean[300];
for (int j = i; j < s.length(); j++) {
if(num[s.charAt(j)]){
break;
}
num[s.charAt(j)]=true;
length=Math.max(length,j-i+1);
}
}
return length;
}
}
但是暴力解时间复杂度太高,为o(n*n)
这里参考kmp算法,改进代码,我们将每一次访问的元素的下标存起来,当重复时,让j等于旧元素下标+1,然后更新下标为新元素下表。同时,可能遇到abba这种字符串,处理这种字符串时,j会指向比当前元素下标更小的元素下标,比如j=2,执行过程中j可能会变成1。所以这里要加判断。
class Solution5 {
public int lengthOfLongestSubstring(String s) {
int length=0;
HashMap<Character, Integer> map=new HashMap<>();
int j=0;
for (int i = 0; i < s.length(); i++) {
if(map.containsKey(s.charAt(i))){
if(j<=map.get(s.charAt(i))){
j=map.get(s.charAt(i))+1;
}
map.put(s.charAt(i),i);
}
else{
map.put(s.charAt(i),i);
}
length=Math.max(length,i-j+1);
}
return length;
}
}
总结
对于本题,利用到滑动窗口的思想
其实就是一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,我们要移动这个队列!
如何移动?
我们只要把队列的左边的元素移出就行了,直到满足题目要求!
一直维持这样的队列,找出队列出现最长的长度时候,求出解!
还利用到了极其重要的数据结构——哈希表