思路:解决此类问题的算法一般是应用滑动窗口,设置一个start作为窗口的左界,end作为窗口的右界,如下图所示:
同时需要一个Map<Character,Integer>来保存特定字符最近出现的索引。在遍历字符串的每个字符时,都要对其对应的val进行更新,对当前已知的最长字串长度进行更新,如果是与之前重复过的字符,则还要更新滑动窗口的左界start,将start调整为上一次遇到这个字符的下一个位置,这样保证当前滑动窗口内不存在重复字符。
下面是具体的代码:
public int lengthOfLongestSubstring1(String s) {
Map<Character, Integer> map = new HashMap<>();
int ans = 0;
for (int start = 0, end = 0; end < s.length(); end++) {
char c = s.charAt(end);
//如果遍历遇到重复的字符串,则对start做出更新
if (map.containsKey(c)) {
start = Math.max(map.get(c) + 1, start);
}
//对字符索引进行更新
map.put(c, end);
//对当前已遍历过的字符串字串的最大无重复字串进行更新
ans = Math.max(end - start + 1, ans);
}
return ans;
}
下面是不采用HashMap,而采用asc码和数组的方式对字符串中的字符进行索引保存的算法:
public int lengthOfLongestSubstring2(String s) {
int ans = 0;
int[] dict = new int[128];
//将数组初始化为-1,便于计算传入字符串为空的情况
Arrays.fill(dict, -1);
//保存最近遇到的重复字符的索引
int base = 0;
int end = 0;
while (end < s.length()) {
//获取字符的asc码
int asc = s.charAt(end);
//发现重复字符,用base对重复字符的索引进行保存
if (dict[asc] > base)
base = dict[asc];
//更新字符的出现索引
dict[asc] = end + 1;
//更新已遍历字符串的最长无重复子串的的长度
ans = Math.max(dict[asc] - base, ans);
end++;
}
return ans;
}