题目解析
算法讲解
算法1: 暴力枚举
枚举「从每⼀个位置」开始往后,无重复字符的子串可以到达什么位置。找出其中长度最大的即
可。
在往后寻找无重复子串能到达的位置时,可以利用「哈希表」统计出字符出现的频次,来判断什么
时候子串出现了重复元素
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int ret = 0; // 记录结果
int n = s.length();
// 1. 枚举从不同位置开始的最⻓重复⼦串
// 枚举起始位置
for (int i = 0; i < n; i++)
{
// 创建⼀个哈希表,统计频次
int hash[128] = { 0 };
// 寻找结束为⽌
for (int j = i; j < n; j++)
{
hash[s[j]]++; // 统计字符出现的频次
if (hash[s[j]] > 1) // 如果出现重复的
break;
// 如果没有重复,就更新 ret
ret = max(ret, j - i + 1);
}
}
// 2. 返回结果
return ret;
}
};
算法2: 滑动窗口
让滑动窗⼝满⾜:窗⼝内所有元素都是不重复的。
做法:右端元素 ch 进⼊窗⼝的时候,哈希表统计这个字符的频次:
▪ 如果这个字符出现的频次超过 1 ,说明窗⼝内有重复元素,那么就从左侧开始划出窗⼝,
直到 ch 这个元素的频次变为 1 ,然后再更新结果。
▪ 如果没有超过 1 ,说明当前窗⼝没有重复元素,可以直接更新结果
注意:这里左侧为什么需要划出窗口:1. 这个操作是滑动窗口的固定操作 2. 根据这道题来说,左侧的窗口值(Hash表里面的val)需要进行清零(划出)
class Solution {
public:
int lengthOfLongestSubstring(string str) {
//使用滑动窗口 辅助Hash
int left= 0;
int right = 0;
char Hash[128] = {0};
int len = INT_MIN;
//窗口枚举以left为起始的滑动
while(left < str.size())
{
//进窗口
while(right < str.size() && Hash[str[right]] < 1)
{
Hash[str[right++]]++;
}
//走到这里就是已将出现重复元素 出窗口 重复元素使当前的right 但是此时的Hash里面已经不是 无重复的了
len = max(len, right - left);
while(str[left] != str[right])
{
Hash[str[left++]] = 0;
}
Hash[str[left++]] = 0;
}
if(len == INT_MIN)return 0;
return len;
}
};