给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。提示:
0 <= s.length <= 5 * 104s由英文字母、数字、符号和空格组成
暴力破解(超时)
同样,这道题我们还是先研究一下暴力破解,找到规律进行优化!
首先我们得做个小优化,因为我们在遍历字符串的时候,是根据是否出现了重复字符来判断是否符合要求,那么我们可以使用哈希表,将遍历过的字符进行映射!
也就是说,枚举「从每一个位置」开始往后,无重复字符的子串可以到达什么位置,找出其中长度最大的即可。在往后寻找无重复子串能到达的位置时,可以利用「哈希表」统计出字符出现的频次,来判断什么时候子串出现了重复元素。
class Solution {
public:
int lengthOfLongestSubstring(string s)
{
int hash[128] = { 0 }; // 哈希表
int maxlen = 0;
for(int left = 0; left < s.size(); ++left)
{
for(int right = left; right < s.size(); ++right)
{
hash[s[right]]++; // 统计出现的字符次数
if(hash[s[right]] > 1)
break; // 出现了重复的则说明以left开头的就不会连续了,则left++后重新开始
maxlen = max(maxlen, right - left + 1);
}
}
return maxlen;
}
};滑动窗口
同样,暴力解法的思路是正确的,但是没有将双指针发挥好,和上一道题一样,其实 right 指针没必要回退到 left 处重新再向后走,是可以保留在原地的!为什么呢❓❓❓
因为虽然当前 nums[right] 字符是重复字符了,也就是说明以 left 开头的连续子串就结束啦,没有意义往后再遍历了,所以此时让 left++,来看看以其它 left 开头的连续子串的长度是否更长。重点来了,从 [left, right-1] 其实这段区间是之前已经遍历过的不会重复的区间,那么我们就没必要让 right 回退然后重新遍历这段不重复的区间!
但是因为 nums[right] 这个重复字符,不一定是 nums[left],可能是 [left, right-1] 区间的某一个字符,假设这个字符的下标为 index,此时如果我们考虑了加入重复 right 之后,那么我们就得将 index 之前包括 index 处的字符都去掉,也就是说保留 [index+1, right] 区间的字符作为一个新的字符串,此时的 left 就变成了 index + 1,因为从 index + 1 之前开始遍历 left 的话,是会存在 nums[right] 这个重复字符的,是没有意义去遍历的!
简单地说,就是如果遇到了重复字符 nums[right],那么就让 left 向后走直到与 nums[right] 重复的字符离开了左边界也就是离开窗口,才能让 nums[right] 加入到窗口继续滑动!
步骤:右端元素 nums[right] 进入窗口的时候,哈希表统计这个字符的频次:
- 如果这个字符出现的频次超过
1,说明窗口内有重复元素,那么就从左侧开始划出窗口,直到nums[right]这个元素的频次变为1,然后再更新结果。 - 如果没有超过
1,说明当前窗口没有重复元素,可以直接更新结果!
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int hash[128] = { 0 }; // 哈希表,这里用一个数组就能表示
int maxlen = 0;
int left = 0, right = 0;
while(right < s.size())
{
hash[s[right]]++; // 统计字符出现次数
while(hash[s[right]] > 1)
{
// 出窗口
hash[s[left]]--;
left++;
}
maxlen = max(maxlen, right - left + 1); // 计算符合条件的子串的最大长度
right++; // 进窗口
}
return maxlen;
}
};