给定一个字符串,在不重复字符的情况下找出最长子字符串的长度。
例如,没有重复字母“abcabcbb”的最长子字符串是“abc”,长度为3。
对于“bbbbb”,最长的子字符串是“b”,长度为1。
- 用一个集合存放当前子串,循环遍历字符串中的字符
- 如果当前集合不包含当前字符,就将其加入集合。并对最长子串的最长长度进行更新
- 如果包含,就需要将该字符第一次出现的前面的所有字符从集合里删除。
- 直到循环结束。
这里自己实现的代码在做第三个步骤的时候,很复杂,然后看了一个别人做的,顿时觉得。。。。
这里很巧妙的使用了一个指针 i ,来实现第三个步骤。利用 i 指针来记录子串开始的位置,然后这样删除的时候就从 i 删除到 第一次重复 字符出现的后一位置;
public int lengthOfLongestSubstring(String s) {
int i = 0, j = 0, max = 0;
Set<Character> set = new HashSet<>();
while (j < s.length()) {
if (!set.contains(s.charAt(j))) {
set.add(s.charAt(j++));
max = Math.max(max, set.size());
} else {
set.remove(s.charAt(i++));
}
}
return max;
}
使用一个map 加上 指针i 和 j 相对于 set集合 减少 删除集合中元素的操作,用一个map 来存放 键值(字符,位置)。不断更新。
public int lengthOfLongestSubstring(String s) {
int ret = 0;
Map<Character, Integer> map = new HashMap<>();
for (int i = 0, start = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (map.containsKey(c))
// 对 窗口起始位置的更新,注意这里是取位置 c 和 start 的最大值
start = Math.max(map.get(c)+1, start);
ret = Math.max(ret, i-start+1);
// 更新 字符 c 的位置或者加入字符 c 或者他的位置
map.put(c, i);
}
return ret;
}
而自己这部分的代码就是没有吃透删除部分,而是用了一个String 来存放当前子串,进行子串的更新。
import java.util.*;
public class Solution {
public int lengthOfLongestSubstring(String s) {
if (s == null)
return 0;
int len = 0;
Set<String> str = new HashSet<>();
String string = "";
for (int i = 0; i < s.length(); i++) {
String cur = s.substring(i, i+1);
if (str.contains(cur)) {
int curIndex = string.indexOf(cur);
String rm = string.substring(0, curIndex + 1);
string = string.substring(curIndex + 1);
if (str.size() > len) {
len = str.size();
}
for (int j = 0; j < rm.length(); j++) {
str.remove(rm.substring(j, j+ 1));
}
str.add(cur);
string = string + cur;
} else {
str.add(cur);
string += cur;
if (str.size() > len) len = str.size();
}
}
return len;
}
}
其实这就是个滑动窗口,i 到 j 之间为窗口的大小,而 i 到 j 的窗口内部没有重复的字符。如果 j 出发生重复,那么 i 就需要到 重复字符第一次出现的下一个位置。