题目
剑指 Offer II 016. 不含重复字符的最长子字符串
思路
总体思路为,计算以每个位置i
结尾的所有子串,看以i结尾的子串的最长不重复子串是多长
因为所有的子串一定以某个位置结尾,而我们计算了以每个位置结尾的情况,所以不会漏掉答案
假设以i-1
结尾的子串,其最长不重复子串的开头为j
现在轮到计算以i
结尾的所有子串了,假设i
位置的字符为c
这里分两种情况,c
之前在字符串中:
-
没出现过
-
则以i结尾的所有子串中,最长的为从j到i,长度为
i - j + 1
-
为什么?
- 因为之前以
i-1
结尾的子串,左边没有延伸到j
的左边,就是因为再延伸就会有重复字符,因此以i
为结尾的子串,左边也不可能超过j
- 同时因为
c
没有在之前出现过,c也不可能和s[j,i-1]
中的字符有重复,即无重复子串的范围最大为[j,i]
- 因为之前以
-
-
出现过,位置为
k
-
如果
k
小于j
,最大无重复子串为s[j,i]
j
往左边移动一位,就会遇到s[j,i-1]
中的重复字符,而k
小于j
,说明在s[j,i-1]
中没有c
,因此可以放心的将c
加入子串中而不会产生重复
-
如果
k
大于等于j
,最大无重复子串为s[k+1,i]
- 因为
k
大于等于j
,也就是说以i
为结尾的子串中,往左最多延伸到k+1
位置,再往左就会遇到k
位置的c
而产生重复。而因为k
大于等于j
,之前在s[j,i-1]
中没有重复字符,因此在s[k+1,i-1]
中也没用重复字符,因此最大无重复子串为s[k+1,i]
- 因为
-
代码
public int lengthOfLongestSubstring(String s) {
if(s.length() == 0) {
return 0;
}
Map<Character,Integer> map = new HashMap<>();
int j = 0;
map.put(s.charAt(0),0);
int max = 1;
for (int i = 1;i<s.length();i++) {
if (map.containsKey(s.charAt(i))) {
int k = map.get(s.charAt(i));
if (k >= j) {
j = k + 1;
}
}
map.put(s.charAt(i),i);
max = Math.max(max,i - j + 1);
}
return max;
}