描述
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
题解
从左边字符开始向右寻找最长符合要求的字符串,找到之后从左边第二个字符开始再次寻找…当左边开始的字符已经是最后一个字符了我们的遍历就结束了,这很暴力。优化!
维护一个滑动窗口,窗口内(当前窗口l到r)都是没有重复的字符,判断窗口外的下一个字符r+1是否在窗口内出现过,没有出现过去尽可能的扩大窗口的大小,窗口不停的向右滑动r++。
- 如果当前遍历到的字符从未出现过,那么直接扩大右边界r++;
- 如果当前遍历到的字符出现过,则缩小窗口(左边索引向右移动)l–,然后继续观察当前遍历到的字符;
- 重复上述步骤,直到左边索引无法再移动(到达字符串长度);
- 维护一个最大窗口长度length,每次用出现过的窗口大小来更新最大窗口长度length,最后返回length。
代码
public static int lengthOfLongestSubstring(String s) {
int maxLen = 0;//最大窗口长度
int l=0,r=-1 ;//r作为当前遍历字符,初始化-1时便于理解窗口外下一个字符r+1,左边界初始化0
int[] hashIndexs=new int[256];
Arrays.fill(hashIndexs,0);//建立字符和其出现位置之间的映射,字符从a到z对应的ASCLL码97到122,出现一次则加1,保证窗口内字符只出现过一次,映射值都为0
while (l<s.length()){
//如果窗口的下一个字符r+1在窗口未出现过,且下一个字符未超出字符串边界
if(r+1<s.length()&&hashIndexs[s.charAt(r+1)]==0){
r++;
hashIndexs[s.charAt(r)]++;//出现次数
}else {
//窗口左边界右移,移出去的字符出现次数减去一
hashIndexs[s.charAt(l)]--;
l++;
}
if(r-l+1>maxLen){
maxLen=r-l+1;
}
}
return maxLen;
}
另一种解法
创建hash数组,填入的值为该字符在原字符串中的下标
取最近出现的两次下标的最大值
取全局最大值
public static int lengthOfLongestSubstring(String s) {
int curLen=0;
int maxLen=0;
int[] hashIndexs=new int[256];
Arrays.fill(hashIndexs,-1);//填充各字符出现值都为-1
for(int curI=0;curI<s.length();curI++){
//curI为字符串第几个字符
int preI=hashIndexs[s.charAt(curI)];//获取当前下标对应字符在hash表中的值,第一次为-1,后面更新为字符串中字符下标值,取最大的两者差值
if(preI==-1||curI-preI>curLen){
curLen++;//当前不重复字符串长度
}else{
maxLen = Math.max(maxLen, curLen);
curLen=curI-preI;
}
hashIndexs[s.charAt(curI)]=curI;
}
maxLen = Math.max(maxLen, curLen);
return maxLen;
}