给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成
思路:双指针 左指针放在循环里面 右指针依次往右移动
左指针指向一个无重复字符串的开头
右指针指向一个无重复字符的结尾的后一个元素
左指针遍历整段字符串 不断更新ans 得到答案
具体的:
如果确定了开头i左指针的位置,这个是容易的,那么右指针要如何移动,来保证(l,r)区间内的所有字符都是不重复的,这里要用到c++一个容器: unorider_set (无序集合)
C++ STL unordered_set容器完全攻略 (biancheng.net)
所需掌握的方法 count(),统计某个元素的个数(0或1)
insert()向set添加元素
erase()向set删除元素
掌握了以后,r从l开始遍历,如果s[r]对应的count=0那么r对应的字符符合,r往后走;
一直移动到第一个不符合位置的地方即此时无重复字符末尾的后一个元素;
那么此时[l,r-1]区间内的字符串是无重复的,那么可以得到长度 =(r-1-l)+1=r-l ,比较ans,更新;
然后可以进行下一轮获取无重复字符串的步骤了;
那么此时,左指针要往后移一个单位;即体现在循环中i++;
此时的左指针l(也就是i),右指针r,其中的一个区间[l,r-1]一定是无重复的字符串;
那么此时,r应当从当前的位置开始,借助unorder_set不断后移,直至又得到一个新的无重复字符串;
但是,其实这样子还是有点问题的,因为在[0,l-1]区间内的字符都已经被insert到容器里面了,我们为了防止不影响后续r后移的过程中count的判断,需要将[0,l-1]区间内对应的字符全部删除;这是一个一次性批量操作,我们要怎么做到?
其实可以通过i每往右移动一个单位,就可以erase掉s[i-1],这样就能保证比如当i移动到第m个字符的时候,前[0,m-1]个字符都已经被删掉了;
当然这里i>=1,i=0特判即可;
class Solution { public: int lengthOfLongestSubstring(string s) { unordered_set<char> occ; int ans = 0,r = 0,len = s.size(); for (int i = 0;i<len;i++) { if (i==0) { while(!occ.count(s[r])&&r<len) { occ.insert(s[r]); r++; } ans = max(ans,r); } else { occ.erase(s[i-1]); while(!occ.count(s[r])&&r<len) { occ.insert(s[r]); r++; } ans = max(ans,r-i); } } return ans; } };