题目是P3无重复字符的最长子串
对于字符串abcbcbb而言,我们从头遍历,查找以遍历处开始往后的最长不重复子串,如下:
以 (a)bcabcbb 开始的最长字符串为 (abc)abcbb;
以a(b)cabcbb 开始的最长字符串为 a(bca)bcbb;
以ab( c )abcbb 开始的最长字符串为 ab(cab)cbb;
以abc(a)bcbb 开始的最长字符串为 abc(abc)bb;
以abca(b)cbb 开始的最长字符串为 abca(bc)bb;
以abcab( c )bb 开始的最长字符串为 abcab(cb)b;
以abcabc(b)b 开始的最长字符串为 abcabc(b)b;
以abcabcb(b) 开始的最长字符串为 abcabcb(b)。
我们可以发现,如果我们依次枚举子串的起始位置,那么子串的结束位置也是递增的,此结论很容易证明为真,因此我们考虑用这一性质,采用滑动窗口的方法来解决问题:
- 我们使用两个指针来记录:左指针i记录了当前遍历的位置也即滑动窗口的左起始点的位置;右指针right记录了滑动窗口的截至位置,无重复子串的长度即为right-i+1
- 在每一步的操作中,我们将左指针右移一位,然后不断的右移右指针,直到发现重复的元素为止,记录下以i为起始结点的子串的长度
- 枚举结束后,所有记录的长度的最大值即为最长的无重复字符子串
代码如下:
int lengthOfLongestSubstring(string s) {
unordered_set<char>se;
int n=s.size();
int ans=0;
int right=-1;
for(int i=0;i<n;i++){
if(i!=0) se.erase(s[i-1]); //擦去左指针的前一个元素
while(right+1<n&&se.count(s[right+1])==0){ //右指针的下一位如果没出现过
se.insert(s[right+1]); //插入下一个元素
++right; //右指针右移
}
ans=max(ans,right-i+1); //时刻记录每一次遍历后的最大长度
}
return ans;
}