Given a string, find the length of the longest substring without repeating characters.
Example 1:
Input: “abcabcbb”
Output: 3
Explanation: The answer is “abc”, with the length of 3.
Example 2:
Input: “bbbbb”
Output: 1
Explanation: The answer is “b”, with the length of 1.
Example 3:
Input: “pwwkew”
Output: 3
Explanation: The answer is “wke”, with the length of 3.
Note that the answer must be a substring, “pwke” is a subsequence and not a substring.
1,挨个去找出子串,判断里面是否包含重复字符
/**
* 计算不包含无重复子串的长度
* 思路:逐个检查所有的子字符串,看它是否不含有重复的字符
* 效率低下
* @param s
* @return
*/
public int lengthOfLongestSubString(String s){
int length = 1;
if(s == null || s.length()== 0 ){
return 0;
}
if(s.length() == 1){
return length;
}
String maxString = "";
for(int i = 0; i < s.length(); i++){
String sub = String.valueOf(s.charAt(i));
for(int j = i+1; j < s.length(); j++){
char tempChar = s.charAt(j);
if(sub.indexOf(tempChar) != -1){
//每次跳出循环时候,需要比较当前
// 最大的字符串与目前得到的字符串的长度
if(maxString.length() < sub.length()){
maxString = sub;
}
break;
}else{
sub += tempChar;
}
//每次跳出循环时候,需要比较当前
// 最大的字符串与目前得到的字符串的长度
if(maxString.length() < sub.length()){
maxString = sub;
}
}
}
length = maxString.length();
System.out.println("maxString = [" + maxString + "]");
return length;
}
第二个思路,采用滑动窗口的方式,【i, j)在第J个字符时,是否包含,包含的话,则添加进去,否则进行【i+1,j)
详细的思路,可以参见力扣上面的官方说明:
算法
暴力法非常简单,但它太慢了。那么我们该如何优化它呢?
在暴力法中,我们会反复检查一个子字符串是否含有有重复的字符,但这是没有必要的。如果从索引 ii 到 j - 1j−1 之间的子字符串 s_{ij}s
ij
已经被检查为没有重复字符。我们只需要检查 s[j]s[j] 对应的字符是否已经存在于子字符串 s_{ij}s
ij
中。
要检查一个字符是否已经在子字符串中,我们可以检查整个子字符串,这将产生一个复杂度为 O(n^2)O(n
2
) 的算法,但我们可以做得更好。
通过使用 HashSet 作为滑动窗口,我们可以用 O(1)O(1) 的时间来完成对字符是否在当前的子字符串中的检查。
滑动窗口是数组/字符串问题中常用的抽象概念。 窗口通常是在数组/字符串中由开始和结束索引定义的一系列元素的集合,即 [i, j)[i,j)(左闭,右开)。而滑动窗口是可以将两个边界向某一方向“滑动”的窗口。例如,我们将 [i, j)[i,j) 向右滑动 11 个元素,则它将变为 [i+1, j+1)[i+1,j+1)(左闭,右开)。
回到我们的问题,我们使用 HashSet 将字符存储在当前窗口 [i, j)[i,j)(最初 j = ij=i)中。 然后我们向右侧滑动索引 jj,如果它不在 HashSet 中,我们会继续滑动 jj。直到 s[j] 已经存在于 HashSet 中。此时,我们找到的没有重复字符的最长子字符串将会以索引 ii 开头。如果我们对所有的 ii 这样做,就可以得到答案。
实现的代码参见如下
/**
* 思路:采用滑动窗口的方式来实现
* @param s
* @return
*/
public int lengthOfLongestSubString1(String s){
int n = s.length();
SetsubString = new HashSet<>();
int maxLength =0,i = 0,j =0;
while( i < n && j < n){
//【i,j)看看第j个字符是否包含在里面,不包含的话添加进来
if(!subString.contains(s.charAt(j))){
subString.add(s.charAt(j++));
maxLength = Math.max(maxLength,j-i);
}else{
// System.out.println("subString = [" + subString.toString() + "]");
subString.remove(s.charAt(i));
i++;
}
}
return maxLength;
}