在给定的字符串中找出不含重复元素的最长子串的长度,好像比前两题复杂了那么一些。
—————————————————————————
最简单能想到的办法就是:
从第一个字符开始遍历,遇到重复的元素时停止,记录长度,得到从第一个字符开始能够得到的不含重复元素的最大子串。
然后以此类推,可以得到从第二个,第三个等等。
感觉是个非常可靠的思路,不过两个循环嵌套,时间复杂度为n平方。
—————————————————————————
我们可以通过一个例子来看看时间都去哪了:
比如对如下这个字符串遍历
123451
第一次遍历的结果
(12345)1
从第一个字符开始得到的子串长度为5,除了这个信息之外,我们还可以得到一个信息:前五个字符不重复
然后第二次遍历的结果
1(23451)
有没有发现我们在第一次遍历时就已经确定的信息:前五个字符不重复在我们第二次遍历时又重新挨个确定了其中的四个也就是(2345),这样就显得非常呆了。
—————————————————————————
我们来考虑一个非常大胆的想法:
当我们第一次遍历结束时,会得到一个子串(12345)1
然后我们第二次遍历时,子串的起点确定是第二个字符也就是2,但我们遍历的起点可不可以直接从5开始呢?
把(2345)当做一个整体,这样就不会浪费之前遍历得到的信息。
需要两个指针来分别记录子串的首尾,“双指针”。
大致的代码应该是这样的,我随便写一下:
int maxl =0;
int n = s.length();
Set<Character> has =
new HashSet<Character();
int rk =-1;
for(int i =0; i<n; ++i){
//在第一次之后的遍历中,每次开始之前先从哈希集合中删掉上次循环开始的位置的字符
if(i!=0){
has. remove(s.charAt(i-1));
}
while(rk+1<n&& !has.contains(s.charAt(rk+1)){
has. add(s.charAt(rk+1);
++rk;
}
max = Math. max(maxl,rk-i+1);
}
return maxl;
涉及的数据结构哈希我们在第一题就遇到过了,就不再浪费时间了。涉及到哈希的三个方法add() contains() remove()通过英文单词的意思就可以得到用法。