解法一,最简单粗暴的方式
从字符串的第一个字符开始,遍历一遍,看以该字符开始的字符串里,最长的没有重复字符的子串的长度是多少,遍历一遍之后,最大的就是最后的解
public class LengthOfLongestSubstringWithoutRepeatingCharacters {
public int lengthOfLongestSubstring(String s) {
HashMap<String, Boolean> map = new HashMap<>(128);
int result = 0;
for (int i = 0; i < s.length(); i++) {
int tmp = getCur(s, i, map);
if (tmp > result) {
result = tmp;
}
}
return result;
}
private int getCur(String s, int startIndex, HashMap<String, Boolean> map) {
int result = 0;
for (int i = startIndex; i < s.length(); i++) {
String curStr = s.substring(i, i + 1);
if (map.get(curStr) != null && map.get(curStr)) {
map.clear();
return result;
} else {
result++;
map.put(curStr, true);
}
}
map.clear();
return s.length() - startIndex;
}
@Test
public void main() {
System.out.println(lengthOfLongestSubstring(""));
// System.out.println("111");
}
}
解法二,对上述解法的优化
举个简单的例子,字符串abcdxcefgxyz,从a开始计算不重复的子串,当发现c重复的时候,下一轮还用从b开始吗?
不用,因为从b计算,到第二个c也是会重复的。
同样的道理,也不用从c开始计算。下一轮从d开始计算就可以了。
而且从d开始计算的时候,也不用完全从d开始,d是第一个,x是第二个,c是第三个这样,而是可以复用上一轮计算的结果,因为d,x,c这几个都已经比较过了,从d开始子串,长度起码已经是3了,下次只有从e开始比较就可以了。
HashMap<String, Integer> map = new HashMap<>(128);
int result = 0;
int curLenth = 0;
for (int i = 0, j = 0; i < s.length(); i++) {
for (; j < s.length(); j++) {
String curStr = s.substring(j, j + 1);
if (map.get(curStr) != null) {
if (curLenth > result) { // 如果有重复字符,则记录一下当前值
result = curLenth;
}
for (int k = i; k < map.get(curStr); k++) {
map.remove(s.substring(k, k + 1));
}
i = map.get(curStr); // 下一次可以跳过中间的几次检查
curLenth = j - i; // 下一次检查时,curLenth可以而复用现在的一部分值
map.put(curStr, j);
j++;
break;
} else {
curLenth++;
map.put(curStr, j);
}
}
if (curLenth > result) {
result = curLenth;
}
}
return result;