无重复字符的最长子串基础题

class Solution {
public:
int lengthOfLongestSubstring(string s) {
// 哈希集合,记录每个字符是否出现过
unordered_set occ;
int n = s.size();
// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
int rk = -1, ans = 0;
// 枚举左指针的位置,初始值隐性地表示为 -1
for (int i = 0; i < n; ++i) {
if (i != 0) {
// 左指针向右移动一格,移除一个字符
occ.erase(s[i - 1]);
}
while (rk + 1 < n && !occ.count(s[rk + 1])) {
// 不断地移动右指针
occ.insert(s[rk + 1]);
++rk;
}
// 第 i 到 rk 个字符是一个极长的无重复字符子串
ans = max(ans, rk - i + 1);
}
return ans;
}
};
问:这段代码我没有找到他是如何判断指针内外有没有重复的字符,运用了什么原理
问: int rk = -1, 他的右指针的初始值是—1,那他的左指针的初始值呢。
问: // 枚举左指针的位置,初始值隐性地表示为 -1
for (int i = 0; i < n; ++i) {
if (i != 0) {
// 左指针向右移动一格,移除一个字符
occ.erase(s[i - 1]);
}
while (rk + 1 < n && !occ.count(s[rk + 1])) {
// 不断地移动右指针
occ.insert(s[rk + 1]);
这个从头到尾我都没见到他是如何判断是否有重复的字符,我只看到了左右指针不停地移动,他这个左右指针是如何协调的呢

  1. 用的unordered_set判断是否有重复,这个是c++基础库中提供的一个模板。类似set,用来去重
    occ.count(s[rk + 1]),判断是否已经存在,如果存在会返回1。不存在返回0
  2. 左指针就是i,初始值为0
  3. 比如字符串abcdeaf
    左指针i = 0, 右指针rk可以一直累加到4也就是e的位置。然后继续累加会有重复'a',结束右指针的循环。ans = 5
    然后左指针i = 1,并删除unordered_set中的a,右指针rk可以继续累加到f位置。ans = 6
    然后左指针i = 2,右指针已经到了末尾,不用循环了,此时得到ans 仍然为6
    后序移动左指针都是无效操作了,因为不可能再比ans大
  • 要先明白一个方法: 设定从左指针到右指针中保存的是所有无重复的字符, 为了满足这个设定, 开始的时候, 把右指针初始化为-1, 左指针初始化为0, 这是为了保证刚开始遍历的时候左右指针之间一个字符都没有; 然后我们去移动右指针, 是去判断当前右指针的下一个字符是否与当前左右指针之间的值有重复, 所以要rk + 1, 然后再来看你的问题

  • 答问1:通过字典occ中字符的个数判断, 即 occ.count(s[rk + 1] , 你的字典occ中保存的是当前左右指针之间的值, rk + 1是下一个字符, 只要occ中出现该字符的次数为零, 那么就说明下一个字符与左右指针之间的字符都不重复, 可以添加进occ中

  • 答问2: 如上面所描述的, 左指针为0, 右指针为-1, 你知道区间吧,[0, -1]表示前闭后闭区间, 此时里面一个数都没有, 这用于表示在循环开始之前最长不重复字符长度为0; 然后再去判断下一个rk + 1时, 此时就是[0, 0]
  • 答问3: 与问题1重复了, 他就是看字典中是否出现过了该字符了; 我想你应该问的是, 如果出现重复他是怎么办的。 可以看到for循环中的那个while, 如果一直不出现循环, 那就一直只移动右指针就是(即扩大左右指针之间的宽度), 如果出现了重复, 他是不会执行while的, 直到occ.erase(s[i - 1]);这个删除操作, 将左右指针之间的重复的内容删除
  • 不懂可以问, 懂了点个采纳