无重复字符最长子串
给定一个字符串 s
,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是"abc",所以其
长度为 3
方法一
基本思路:滑动窗口
什么是滑动窗口?
其实就是一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,我们要移动这个队列!
如何移动?
我们只要把队列的左边的元素移出就行了,直到满足题目要求!
一直维持这样的队列,找出队列出现最长的长度时候,求出解!
作者:powcai
链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/solutions/3982/hua-dong-chuang-kou-by-powcai/
来源:力扣(LeetCode)
int que_find(char *que, char *s, int len) //遍历数组,寻找是否存在与*s相同的元素 { for(int i = 0; i < len; i++) { if(*s == *(que + i)) return 1; } return 0; } int lengthOfLongestSubstring(char * s){ int len = strlen(s); char *que = malloc(sizeof(char)*len); //注意malloc()分配的使用,直接使用malloc(sizeof(s))会产生下图报错信息 int max_len=0, cur_len=0; int end = 0, start = 0; for( long int i =0; i< len; i++) { cur_len += 1; while(que_find(que, s+i, len)) //注意这个循环,它的作用是循环将与*(s + i)相同的元素删除 { *(que + start) = 0; //delete start += 1; cur_len -= 1; } *(que + end) = *(s + i); //元素入队 end += 1; if(cur_len > max_len) //记录最长子串 max_len = cur_len; } return max_len; }
滑动窗口算法主要应用对象:数组和字符串
结合滑动窗口算法的说明和本例题,可知滑动窗口算法可以用来解决一些查找满足一定连续区间的性质(长度)的问题,
因此当区间发生了变化(不满足给定条件)时,可以通过旧有的计算结果(窗口)对搜索空间进行剪枝,从而达到减低时间复杂度的效果
类似于“找到满足 xx 的最 x 的区间(子串、子数组)的 xx”的问题,都可以使用滑动窗口解决。
注意:滑动窗口是一种思想、算法,不用拘泥于数据结构。(不一定要用队列求解本例)
滑动窗口基本框架
- 滑动:窗口是移动的,方向是我们根据要求自己设定
- 窗口:窗口大小不一定是固定的,它可以随时改变,根据需要扩大(直到满足一定条件)或缩小(直到找到一个满足条件的最小窗口);也能保持固定
结合本题,深入理解滑动窗口算法,并将其抽象
- 我们在字符串 S 中使用双指针中的左右指针技巧,初始化 left = right = 0,把索引闭区间 [left, right] 称为一个「窗口」
- 我们先不断地增加 right 指针扩大窗口 [left, right],直到窗口中的字符串符合要求(无重复字符)
-
此时,我们停止增加 right,转而不断增加 left 指针缩小窗口 [left, right],直到窗口中的字符串不再符合要求(直到与*(s+i)无重复)。同时,每次增加 left,我们都要更新一轮结果。
- 重复第 2 和第 3 步,直到 right 到达字符串 S 的尽头
以下是更高效的程序例程
int lengthOfLongestSubstring(char * s) { int len = strlen(s); if (len <= 1) { return len; } char *left = &s[0]; char *right = &s[0]; //滑动窗口左右指针 int maxLen = 0; int map[256] = {0}; memset(map, 0, sizeof(map)); for (int i = 0; i < len; i++) { map[*right]++; //根据每个字符对应一个ASCII码,每次遍历对应键的值就加1(类似于哈希表) while(map[*right] > 1) { //超过1,说明字符重复,左指针右移 map[*left]--; left++; } right++; maxLen = maxLen < (right - left) ? (right -left) : maxLen; } return maxLen; }
附: