解答:滑动窗口思想(见官方题解)
//方法1
class Solution {
public:
int lengthOfLongestSubstring(string s) {
//哈希表记录是否有重复字符
unordered_set<char>c;
int maxlength=0;
int n=s.size();
//右指针初始化为-1,可以假设为一开始还没窗口
int r=-1;
//左指针就是每次循环的i
for(int i=0;i<n;i++){
//滑动窗口每次移动时,左指针需要向右边移动一个单位,那么要把哈希表的记录也同步删去
if(i!=0){
c.erase(s[i-1]);
}
//右指针可以一直移动,找到最大的无重复字符串的地方
while(r+1<n&&c.count(s[r+1])==0){
//在哈希表中记录新的字符
c.insert(s[r+1]);
r++;
}
//r是窗口右边的位置,i是窗口左边位置,长度就是r-i+1
maxlength=max(maxlength,r-i+1);
}
return maxlength;
}
};
//方法2
class Solution{
public:
int lengthOfLongestSubstring(string s) {
//使用大小为128的数组m(对应ASCII字符集)记录每个字符最近出现的索引加1(如字符在位置j出现,则存储为j+1)。
vector<int>m(128,0);
int i=0;//左窗口边界
int ans=0;
//右窗口边界移动
for(int j=0;j<s.size();j++){
//在遍历字符串时,右边界j逐个移动,我们需要检查当前字符s[j]的上次出现位置
//如果上次出现的位置在左边界i的右侧,证明现在这个窗口已经有重复字符s[j]了,左边界必须移动到新的位置,也就是上次s[j]出现的位置+1
i=max(i,m[s[j]]);
m[s[j]]=j+1;//更新s[j]的最新位置为j+1
ans=max(ans,j-i+1);
}
return ans;
}
};
方法1解析:
(1)时间复杂度O(n)
(2)空间复杂度O(n)
方法2解析:
(1)时间复杂度O(n)
(2)空间复杂度O(1):固定大小的数组存储字符位置。
(3)思想:通过维护左边界i和字符位置映射,动态调整窗口范围,确保无重复字符。利用字符上次出现位置的“索引+1”快速定位左边界需移动的位置。