题目:
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
思路:
滑动窗口法:
思路和算法
我们先用一个例子来想一想如何在较优的时间复杂度内通过本题。
我们不妨以示例一中的字符串 exttt{abcabcbb}abcabcbb 为例,找出 从每一个字符开始的,不包含重复字符的最长子串,那么其中最长的那个字符串即为答案。对于示例一中的字符串,我们列举出这些结果,其中括号中表示选中的字符以及最长的字符串:
判断重复字符
在上面的流程中,我们还需要使用一种数据结构来判断 是否有重复的字符,常用的数据结构为哈希集合(即 C++ 中的 std::unordered_set,Java 中的 HashSet,Python 中的 set, JavaScript 中的 Set)。在左指针向右移动的时候,我们从哈希集合中移除一个字符,在右指针向右移动的时候,我们往哈希集合中添加一个字符。
至此,我们就完美解决了本题。
代码如下:
public int lengthOfLongestSubstring(String s) {
int ans = 0;
int rk=0;
HashSet<Character> occ = new HashSet<Character>();
for(int i=0;i<s.length();i++) {
if(i!=0) {
occ.remove(s.charAt(i-1));
}
while(rk<s.length() && !occ.contains(s.charAt(rk))) {
occ.add(s.charAt(rk));
rk++;
}
ans = Math.max(ans, rk-i);
}
System.out.println(ans);
return ans;
}
知识点小结:
这里使用了HashSet创建了character的数组,先让我们了解一下HashSet
HashSet是基于HashMap来实现的,
是一个不允许有重复元素的集合,但是HashSet允许有空值。另外HashSet是无序的,
即不会记录插入的顺序。在线程安全方面,它也不是线程安全的,
如果多个线程尝试同时修改HashSet,则最终的结果是不正确的。
在多线程访问时,必须显式同步对HashSet的并发访问。
一个原因是HashSet创建的数组有remove方法,移除的是元素,不是下标。
而使用ArrayList无法使用remove直接移除数组的元素