LeetCode题库3:无重复字符的最长子串
思路
最容易想到的是两层循环,第一层循环依次选择子串的起始字符;第二层循环检查从这个起始字符开始,最多几个字符之后会出现重复字符。
但是,这样的思路显然不会是最有效率的算法,时间复杂度为O(n2),空间复杂度为O(1)。
简化的方法之一是使用哈希表,将查找的效率提高到O(1),但是我还没看懂哈希表是怎么做到的(捂脸.jpg),所以我希望能换一种更容易理解的算法。
然后我在和无敌小星星散步的时候和他讨论了一下这个问题,回家之后实现了这个算法。
方法大概是这样的:一个指针指向子串头,一个指针指向子串尾,再用一个数组保存ASCII码为n的字符上次在什么地方出现的。
最重要的事情是保证子串中没有重复字符。
在执行过程中,指向子串尾的指针每次循环+1;如果最后一个字符发现是重复字符,就把头指针向前移动,直到字符串里没有重复字符(当然,这个“直到”不是通过循环实现的)。期间要记得对比记录一下max_len和len就行啦
代码
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int len = 0; //当前子串长度
int max_len = 0; //最长子串长度,会用于输出
int head = 0; //记录子串从哪个字符开始
int rep[128]; //记录上一次某个字符出现的位置
for(int i = 0 ; i< 128; i ++){
rep[i] = -1; //初始化为-1
}
int sSize = s.size(); //字符串的长度
for (int i = 0 ; i < sSize; i++){ //循环的i其实是字符串末尾
char ch = s[i];
if(rep[ch] == -1 || rep[ch] < head){ //如果这个字符没有出现过,或者最近一次出现是在head指针前面
rep[ch] = i; // 将字符出现的位置记录下来
len ++;
if(len > max_len){
max_len = len;
}
}else{ // 如果子串中出现了重复字符
head = rep[ch] + 1; // rep[ch]中保存的就是重复字符的位置。将head移到重复字符之后,这样剩余子串中就没有重复字符了
len = i - head + 1;
rep[ch] = i;
}
// printf("i = %d ; ch = %c ; head = %d ; len = %d ; max_len = %d\n",i,ch,head,len,max_len);
}
if(len > max_len){ //更新max_len
max_len = len;
}
return max_len;
}
};