本期给大家带来的是 LeetCode 热题 HOT 100 第三题关于 无重复字符的最长子串 的讲解。首先,我们还是先从题目入手进行分析思考!!!
题目如下 :👇
给定一个字符串
s
,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
💥题意分析
本题的意思很简答,就是给出一串字符,让我们算出字符串中 无重复字符的最长子串,最后返回无重复字符串的长度即可!
🔥图解
找出从每一个字符开始的,不包含重复字符的最长子串,那么其中最长的那个字符串即为答案。我们先按照 示例 3 的输出给大家画图解释一下流程:
- 第一步:
- 第二步:
- 第三步:
-
- 第四步:
- 第五步:
第六步:
当我们进行逐步遍历之后,在把遍历过程中所有的结果进行比较从而找到满足题意的最长的字符串!!!
⭐️ 不知道大家从我们上面给的图中是否发现了一件事 ⭐️:
💨 上述流程图,我们每次子串的起始位置递增的往后移动,随着每次起始位置的移动,紧随的我们后面匹配的子串的结束位置也是往后递增的!!!
上述这一点,我们可以从上述图中发现原因:
- 假设我现在的起始位置就是【第一个的p】的位置,此时它所对应的满足题意的字符串的结束位置为 【第一个w 】的位置
- 那么当我们选择第 【k+1】个字符的位置作为起始位置时,首先从 【k+1】到 【o】位置此时的字符显然是不重复的,并且由于少了原本的第 【k】 个字符,我们可以继续往后增大 【o】位置,直到右侧出现了重复字符为止
因此,这道题的思想即需要用到有关 滑动窗口 的知识!!
💨 解题思路:
前言:
不知道大家有没有听说过有关 滑动窗口协议 这个知识点。
- 该协议是 TCP协议 的一种应用,用于网络数据传输时的流量控制,以避免拥塞的发生。该协议允许发送方在停止并等待确认前发送多个数据分组。由于发送方不必每发一个分组就停下来等待确认。因此该协议可以加速数据的传输,提高网络吞吐量。
- 顾名思义,就像一个滑动的窗口,套在一个序列中,左右的滑动,窗口内就是一个内容集。
- 通过固定左端元素,再把右端元素不断右移,算出左端和右端间的总数,然后左端再不断右移,不断计算之间的总数。最后算出最小长度。
具体步奏:
- 首先我们需要定义两个指针,使用这两个指针表示字符串中的某个子串对应的左右边界,其中左指针代表每次遍历的起始位置,而右指针即为一次遍历中的末尾位置;
- 在每次移动的操作中,我们会将左指针向右移动一位,表示我们下次开始遍历过程的起始位置,然后我们可以不断地向右移动右指针进行遍历操作(需要保证两个指针对应的子串中没有重复的字符)
- 在移动结束后,这个子串就对应着 以左指针开始的,不包含重复字符的最长子串。紧接着我们记录下这个子串的长度
- 最后遍历完成之后,比较所有记录下的子串的长度,找到最大的值输出即可!
代码
class Solution { public: int lengthOfLongestSubstring(string s) { //首先对字符串进行判断,如果为空则返回0 if(s.size() == 0) return 0; //记录字符出现过,此时需要用到 C++ STL标准库中的 unordered_set 容器 unordered_set<char> str; //用于记录最大的字符串长度,初始化为0 int MaxLength=0; //设置的指针 int left=-1; for(int i=0; i<s.size(); ++i) { if( i != 0) //左指针每次向右移动一位字符,移除一位字符 str.erase(s[i-1]); //去进行遍历查找操作 while(left +1 < s.size() && !str.count(s[left+1])) { //不断的向右移动指针 str.insert(s[left+1]); left++; } //此时最大的子串为left位置到 i位置 之间的值 MaxLength=max(MaxLength,left-i+1); } return MaxLength; } };
还有一种方法根据某大佬的写出的:
class Solution { public: int lengthOfLongestSubstring(string s) { //首先对字符串进行判断,如果为空则返回0 if (s.size() == 0) return 0; //记录字符出现过,此时需要用到 C++ STL标准库中的 unordered_set 容器 unordered_set<char> str; //用于记录最大的字符串长度,初始化为0 int MaxLength = 0; //设置的指针 int left = 0; for (int i = 0; i < s.size(); ++i) { //lookup.find() 查找对应元素,成功返回对应的迭代器,失败返回最后一个元素迭代器(即 lookup.end() ) while (left + 1 < s.size() && str.find(s[i]) != str.end()) { //不断从左缩小窗口,直到窗口中不存在与下一个字符重复的字符 str.erase(s[left]); left++; } //此时最大的子串为 i位置 到left位置之间的元素个数 MaxLength = max(MaxLength, i - left + 1); //不断的向右移动指针 str.insert(s[i]); } return MaxLength; } };
到此,关于本题的讲解就到这里了!!