给定一个字符串,找出不含有重复字符的最长子串的长度。
示例:
给定 "abcabcbb"
,没有重复字符的最长子串是 "abc"
,那么长度就是3。
给定 "bbbbb"
,最长的子串就是 "b"
,长度是1。
给定 "pwwkew"
,最长子串是 "wke"
,长度是3。请注意答案必须是一个子串,"pwke"
是 子序列 而不是子串。
暴力解法:
class Solution {
public int lengthOfLongestSubstring(String s) {
int l = s.length();
int max = 0;
for(int i = 0; i < l; i++){
for(int j = i + 1; j <= l; j++){
if(AllUnique(s, i, j)) max = Math.max(max, j - i);
}
}
return max;
}
public boolean AllUnique(String s, int start, int end){
Set<Character> set = new HashSet<>();
for(int i = start; i < end; i++){
Character ch = s.charAt(i);
if(set.contains(ch)) return false;
set.add(ch);
}
return true;
}
}
复杂度分析:
o(n^3)
HashSet的知识点:
HashSet(): 构造一个空的容器,默认容量为16
- hashset.add("abc");
- //向hashset中添加一个整数
- hashset.add(1);
- //向hashset中添加一个字符
- hashset.add('a');
- //向hashset中添加一个数组
- int[] abc={10,11,12};
- hashset.add(abc);
- //向hashset中添加一个自定义对象
- Cat cat1=new Cat("asd", 2);
- hashset.add(cat1);//向hashset中添加一个对象</span>
常用方法:
hashset.add(E e):返回boolean型,如果此 set 中尚未包含指定元素,则添加指定元素;如果此 set 已包含该元素,则该调用不更改 set 并返回 false。
删除元素:
hashset.clear():从此 set 中移除所有元素。
hashset.remove(Object o):如果指定元素存在于此 set 中,则将其移除。
hashset.isEmpty():如果此 set 不包含任何元素,则返回 true。
hashset.contains(Object o):如果此 set 包含指定元素,则返回 true。
hashset.size():返回此 set 中的元素的数量(set 的容量)。
滑动窗口解法:
class Solution {
public int lengthOfLongestSubstring(String s) {
int l = s.length();
int max = 0, i = 0, j = 0;
Set<Character> set = new HashSet<>();
while(i < l && j < l){
if(!set.contains(s.charAt(j))){
set.add(s.charAt(j++));
max = Math.max(max, j - i);
}
else{
set.remove(s.charAt(i++));
}
}
return max;
}
}
Complexity Analysis
Time complexity : O(2n) = O(n)O(2n)=O(n). In the worst case each character will be visited twice by ii and jj.
Space complexity : O(min(m, n))O(min(m,n)). Same as the previous approach. We need O(k)O(k) space for the sliding window, where kk is the size of the
Set
. The size of the Set is upper bounded by the size of the string nnand the size of the charset/alphabet mm.
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
Map<Character, Integer> map = new HashMap<>(); // current index of character
// try to extend the range [i, j]
for (int j = 0, i = 0; j < n; j++) {
if (map.containsKey(s.charAt(j))) {
i = Math.max(map.get(s.charAt(j)), i);
}
ans = Math.max(ans, j - i + 1);
map.put(s.charAt(j), j + 1);
}
return ans;
}
}
现实情况没必要每次都把i一步一步移动,可以将i直接移动至元素重新出现的位置
如此时的窗口的大小为[i, j),如果是s[j]和窗口中的某个元素重复,此时的索引值为j',我们可以直接跳过[i, j']
将此时的窗口大小调整为[j'+1, j)