这道题看起来很容易,就是给一个字符串,然后找子串,比较找出最长的子串。
这就涉及到了最重要的问题,求子串
如果是简单的求出子串,那么两个for循环嵌套就好了。
第一个for循环给出子串的起始坐标,第二个遍历淄川的终止坐标。
但这个题很有意思,让我们找的是子串有特殊属性:其中所有字符不重复!
那么很有意思,有没有简化的方法来遍历字符不重复的子串
遍历字符不重复的子串
最好的遍历方法就是滑动窗口法
我们来想象一下,有一个可以左右拉伸的窗口,这个窗口的宽度从0开始变大变小,开始的时候,窗口左端边与字符串第一个字符对其,然后窗口的右端边从字符串的第二个字符开始准备向右跑,窗口左端边也准备向右跑,具体怎么跑可以遍历所有不重复子字符串呢?规则如下:
保证窗口内的字符都是不重复的,利用窗口的蠕动变换遍历所有不重复子字符串
右端边遇到的字符不在窗口内,呢么右端边向右一下,把这个不在窗口内的字符包进来,一直重复这个操作(窗口右端不断拉长),直到遇到一个已经在窗口内的字符。这个时候窗口窗口的左端右移,然后继续判断哪个字符是不是在窗口内,如果还在窗口内,窗口左端就继续右移,直到哪个字符不在窗口内,然后窗口右端右移把这个字符包进来,这样一直做,最后窗口的右端到了字符串右边界,即可遍历完所有不重复的子串.
我们先来看看暴力求解的代码:
class Solution{
public int lengthOfLongestSubstring(String s){
if(s.isEmpty()){
return 0;
}
int ans=1;
for(int i=0;i<s.length();i++){
for(int j=i+1;j<s.length();j++){
if(isUnique(s,i,j)){
if(ans<j-i+1){
ans=j-i+1;
}
}
}
}
return ans;
}
public boolean isUnique(String str,int index1,int index2){
boolean result=true;
Set<Character> mySet=new HashSet<Character>();
for(int i=index1;i<=index2;i++){
if(mySet.contains(str.charAt(i))){
result=false;
}
else{
mySet.add(str.charAt(i));
}
}
return result;
}
}
果然,系统显示:
超出了时间限制!,想想也是,这种方法时间复杂度为O(n^3),这样都能过也就没天理了。
滑动窗口遍历非重复子串代码实现
class Solution{
public int lengthOfLongestSubstring(String s){
if(s.isEmpty()){
return 0;
}
int length=s.length();
int i=0;//窗口的左端边
int j=0;//窗口的右端边
Set<Character> mySet=new HashSet<Character>();
int ans=1;
while(i<length&&j<length){
if(!mySet.contains(s.charAt(j))){
mySet.add(s.charAt(j));
j++;
}
else{
mySet.remove(s.charAt(i));
i++;
}
if(ans<mySet.size()){
ans=mySet.size();//到这一步,mySet中元素个数就是该子串不重复元素个数
}
}
return ans;
}
}