【题目描述】
【思路】
暴力做法:
for(i从0到n)
for(j从i到0)
统计子串[j,i]不包含重复字符的最大长度,也就是以i为右端点,j最远能往前走多远
暴力做法是O(n^2)的复杂度,进一步优化。通过暴力做法可以发现,i、j指针具有单调性。j往右移动,i不可能往左移动。
因此可以使用双指针, i在左, j在右。遍历扫描一遍。
class Solution {
public int longestSubstringWithoutDuplication(String s) {
if(s == null || s.length() == 0 ) return 0;
int []hash = new int[26];
char c[] = s.toCharArray();
int res = 0, n = s.length();
for(int i = 0, j = 0; j < n; j ++)
{
hash[c[j] - 'a'] ++;
//右端发生有跟左边元素发生重复 左端i指针往右移动至不重复位置
if( hash[c[j] - 'a'] > 1){
while( i < j){
hash[c[i] - 'a'] --;
i ++;
if( hash[ c[j] - 'a' ] == 1) break;
}
}
res = Math.max(res, j - i + 1);
}
return res;
}
}
使用哈希表
class Solution {
public int lengthOfLongestSubstring(String s) {
/*
双指针维护最长子串区间,i在左 j在右
*/
if(s==null || s.length() == 0){
return 0;
}
int i = -1, j = 0, n = s.length();
char c[] = s.toCharArray();
Map<Character, Integer> map = new HashMap<>(); //统计c[j]最后一次出现的索引
int res = 0;
while(j < n){
if(map.containsKey(c[j])){ // [i, j]区域出现重复
i = Math.max(i, map.get(c[j])); // 获取左指针最右能到达的地方(上一轮c[j]出现的位置)
}
map.put(c[j], j); // 最新的c[j]位置
res = Math.max(res, j - i);
j ++;
}
return res;
}
}