一、题目描述
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
提示:
s.length <= 40000
二、思路讲解
暴力方法,遍历字符串,以每一个字符作为开头,将它及后面的字符怼到HashSet中,如果怼不进去了,那就是重复了,此时集合的大小就是不重复的字串的大小。然后清空集合,再看下一个字符,直到遍历完整个字符串。效率较低。
三、Java代码实现
class Solution {
public int lengthOfLongestSubstring(String s) {
int len = s.length();
int index;
HashSet<Character> set = new HashSet<>();
int big = 0;
for(int i=0; i<len; i++){
index = i;
set.clear();
//把字符后的每一个字符怼进集合中,直到怼不进(说明重复了)或者遍历完了字符串
while(index<len && set.add(s.charAt(index))){
index++;
}
big = Math.max(big, set.size());
}
return big;
}
}
四、时空复杂度分析
时间复杂度: O(N^2)
空间复杂度: O(N)
五、代码优化
想想时间上的优化:能不能仅遍历一遍字符串呢?
我们可以使用滑动窗口的思想。
再想想空间上的优化:能不能用常数级的空间呢?
可以用HashMap,在ASCII码內长度最多为128,占用空间为常数级。
具体思路是:创建一个哈希表,存储字符串中字符的下标,遍历字符串的同时维护一个滑动窗口,左指针j,右指针i,如果i处元素在哈希表中存在,则更新左指针至j、map.get(ch)两者之间的最大值。
class Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character,Integer> map=new HashMap<>();
int len = s.length();
int j = 0;
int big = 0;
for(int i=0; i<len; i++){
char ch = s.charAt(i);
if(map.containsKey(ch)){
j = Math.max(map.get(ch)+1, j);
}
map.put(ch, i);
big = Math.max(big, (i-j+1));
}
return big;
}
}
时间复杂度: O(N)
空间复杂度: O(1)