力扣获取最大无重复字符子串长度C语言实现
最大无重复字符子串长度问题-C语言实现
给定一个字符串 s ,请你找出其中不含有重复字符的最长子串的长度。
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
输入: s = “aaaa”
输出: 1
解释: 因为无重复字符的最长子串是 “a”,所以其长度为 1。
代码实现
int lengthOfLongestSubstring(char * s){
int sLen = strlen(s);
int left = 0, ret = 0, cnt = 0;
int right;
int tmp[128] = {0};//记录某个字符是否已经出现过一次
for(right = 0; right < sLen; right++){
if(0 == tmp[s[right]])//右滑动窗口,如果有一个字符出现过则会进入else移动左窗
{
tmp[s[right]]=1;//记录这个字符是否出现了
cnt++;//窗口长度,也即子串长度
if(cnt > res){
ret = cnt;//ret用来记录找到过的最大无重复子串长度
}
}
else//左滑动窗口,字符有重复,需要找到这个字符
{
/*左窗移动,清空字符记录,直到找到跟右窗口相同的这个字符。
* 一旦需要移动左窗时,就意味着当前右窗的字符在当前左右窗所匹配到的子串中出现过。
* 因此需要移动左窗来找到这个重复字符,并且将左窗当前字符记录清空,
* 以便进入下一轮循环的if判断中,右窗来确认左窗已经找到这个字符。
*/
tmp[s[left]] = 0;//清空当前字符的记录,如果清空的是右窗所在的字符,那么下一轮循环一定会进入if内部移动右窗了。
left++;//左窗移动到下一个
cnt--;//左窗向右移动了,因此需要-1。
right--;//进入下一轮for循环时,i会自动+1。因此此处-1保证右窗位置不变
}
}
return ret;
}
思路
- ASCII码每个字符唯一,因此可以用tmp[128]数组来记录当前字符是否出现了(简化的hash table);
- 滑动窗口:利用双指针索引子串;
- 判断条件:for循环用来移动右窗。假设右窗是可移动的,那么我们需要一直移动右窗,当右窗所在字符前面出现过,那就必须要开始处理左窗来剔除掉这个重复字符,当左窗剔除了这个字符,我们才能继续移动右窗;
- 合理的控制循环体变量能等效于另一个有效for循环;
总结
这个leetcode题目用常规的两层for循环也可以解决问题,但是刷到了评论中一位高手的优化代码。有意思的点在于在循环体中更改循环变量,用来实现第二次for循环。在正常工作中编写代码时,是不建议的循环体中修改循环变量,但是对于代码优化上还是有一定帮助,因此以此作为笔记学习。