解决思路
双指针-滑动窗口
典型的可以使用滑动窗口的问题
**
- 考察从i到j的一个子串s[i,,,j]
- 如果该子串中没有重复的字母,考察j的下一个字母是否与之前的重复
- 如果没有重复,j++。最长的不重复子串变为s[i,….j+1]
- 依次类推,一直到新加入的字母与之前的字母产生了重复
- 此时不能继续向前拓展,[i,…j]为暂时找到的最长子数组。记录其长度
- 然后i++,直到把重复的数字刨除出去
- 然后j就可以包含刚才的重复字符,即j++
- 此时就可以获取一个新的没有重复字符的子串
- j继续向前扩展
如何判断当前字符与之前的子数组是否重复?
设置一个数组 freq[256]
freq[k]存ASCII码为k的字符在子串中出现的频率
如果是0 没有重复,如果是1就有重复
这样就可以用O(1)的时间复杂度来判断每一个字符在当前的子串中是否重复
public int lengthOfLongestSubstring(String s) {
//定义每个字母出现的次数 初始值0 表示没有出现
int freq[] = new int[256];
//滑动窗口为s[l....r]
//l初始为0 r初始为-1 表示[0,-1] 此时滑动窗口内没有数据
int l = 0;
int r = -1;
//用来保存最后的结果
int res = 0;
//如果左边界还可以取值
while(l<s.length()){
//先判断右边是否可以取到 然后判断右边的数字是否已经出现过
//如果没有出现过 右指针移动 将新出现的字母出现次数累加
if( r+1<s.length() && freq[s.charAt(r+1)]==0){
r++;
freq[s.charAt(r)]++;
}
//如果右边的字母已经出现过 去掉左边的数字 将其出现次数-1 并指针右移
else{
freq[s.charAt(l)]--;
l++;
}
//记录最大值
res = res>(r-l+1)?res:r-l+1;
}
return res;
}