题目描述
子串:各字符间必须要相邻,而非子序列 使用滑动窗口 来做就行
思路 && 代码
1. 之前的版本
思路 :维护一个滑动窗口,滑动窗口中容纳一个无重复字符的子串。滑动窗口左边界移动的情况:
【abc】 a => a【bca】 【abcd】 c => abc【dc】 其实以上两种情况殊途同归,都是把左边界 换成当前判断字符在HashMap中对应的下标的位置的后一个 。 然后把前面的字符全都丢弃即可(在HashMap中remove())。 左边界移动的情况,需要进行长度的判断:当前滑动窗口长度可能会改变,如果比当前存储的最大长度要大,那么就需要更新。 为什么可以这样子 :特别记录一下,这道题其实老早就通过了。。但是之后考虑情况多了,出现了觉得自己写的代码其实考虑不周,但是就是过了的情况= =。 主要是有这个注意点 :在上面的左边界移动情况2,考虑到abc都被丢弃,但是有没有可能a、b实际上可能可以创造最长子串呢? 答案是没有 ,因为实际上最多的长度【abcd】已经被记录下来了,b最多就是【bcd】c的情况,a也同理,因此已经可以直接丢弃掉了。
class Solution {
public int lengthOfLongestSubstring ( String s) {
int len= 0 , lenNow= 0 ;
HashMap < Character , Integer > hashMap = new HashMap < > ( ) ;
for ( int i= 0 ; i< s. length ( ) ; i++ ) {
if ( hashMap. containsKey ( s. charAt ( i) ) ) {
if ( hashMap. get ( s. charAt ( i) ) == i- lenNow) {
hashMap. put ( s. charAt ( i) , i) ;
continue ;
}
len = Math . max ( len, lenNow) ;
int temp = hashMap. get ( s. charAt ( i) ) ;
for ( int j = i- lenNow; j<= temp; j++ ) {
hashMap. remove ( s. charAt ( j) , j) ;
}
lenNow = i - temp;
hashMap. put ( s. charAt ( i) , i) ;
}
else {
hashMap. put ( s. charAt ( i) , i) ;
lenNow++ ;
}
}
return Math . max ( len, lenNow) ;
}
}
时间复杂度:O(N) ,实际上整个流程本质上就是对字符串的每一个元素都必然访问一次 ,可能删除一次 。空间复杂度:O(字符集的大小) ,因为我们需要简历哈希表,而表最大的情况下会容纳整个字符集(及对应下标)。
更新 2.0
class Solution {
public int lengthOfLongestSubstring ( String s) {
int len = s. length ( ) ;
int max = 0 ;
char [ ] arr = s. toCharArray ( ) ;
Map < Character , Integer > hashmap = new HashMap < > ( ) ;
int windowLeft = 0 ;
for ( int i = 0 ; i < len; i++ ) {
if ( hashmap. containsKey ( arr[ i] ) ) {
int index = hashmap. get ( arr[ i] ) ;
for ( int j = windowLeft; j <= index; j++ ) {
hashmap. remove ( arr[ j] ) ;
}
windowLeft = index + 1 ;
hashmap. put ( arr[ i] , i) ;
}
else {
hashmap. put ( arr[ i] , i) ;
max = Math . max ( max, hashmap. size ( ) ) ;
}
}
return max;
}
}