LeetCode - 3. 无重复字符的最长子串
目录
题目
解题思路:滑动窗口 + 哈希表
核心思想
详细实现步骤
图解示例
时间和空间复杂度
正确的写法
题目
3. 无重复字符的最长子串 - 力扣(LeetCode)
解题思路:滑动窗口 + 哈希表
滑动窗口是处理子串/子数组问题的常用技巧,结合哈希表可以高效解决此问题。
核心思想
维护一个"窗口",这个窗口内的所有字符都是不重复的。当遇到重复字符时,调整窗口左边界,确保窗口内无重复字符。
详细实现步骤
- 初始化:
- 创建哈希表记录字符出现次数
- 左指针left和右指针right初始化为0
- 最大长度ret初始化为0
- 扩展窗口:
- 右指针right向右移动,将当前字符加入窗口
- 更新哈希表中该字符的计数
- 处理重复:
- 如果当前字符在窗口中已存在(计数>1)
- 不断移动左指针left,同时减少对应字符的计数
- 直到窗口中不再有重复字符
- 更新结果:
- 每次调整窗口后,计算当前无重复子串的长度
- 更新最大长度ret
- 继续扩展:
- 右指针继续向右移动,重复步骤2-4
图解示例
以字符串 "abcabcbb" 为例:
初始状态:
字符串: a b c a b c b b↑l,r
哈希表: {}
最大长度: 0
步骤1:右指针移动到'a'
字符串: a b c a b c b b↑l r
哈希表: {a:1}
最大长度: 1
步骤2:右指针移动到'b'
字符串: a b c a b c b b↑ ↑l r
哈希表: {a:1, b:1}
最大长度: 2
步骤3:右指针移动到'c'
字符串: a b c a b c b b↑ ↑l r
哈希表: {a:1, b:1, c:1}
最大长度: 3
步骤4:右指针移动到第二个'a'
字符串: a b c a b c b b↑ ↑l r
哈希表: {a:2, b:1, c:1}
发现'a'重复,移动左指针直到窗口中'a'不重复:
字符串: a b c a b c b b↑ ↑l r
哈希表: {a:1, b:0, c:0}
最大长度: 3
步骤5:右指针移动到第二个'b'
字符串: a b c a b c b b↑ ↑l r
哈希表: {a:1, b:1, c:0}
最大长度: 3
步骤6:右指针移动到第二个'c'
字符串: a b c a b c b b↑ ↑l r
哈希表: {a:1, b:1, c:1}
最大长度: 3
步骤7:右指针移动到第三个'b'
字符串: a b c a b c b b↑ ↑l r
哈希表: {a:1, b:2, c:1}
'b'重复,移动左指针:
字符串: a b c a b c b b↑ ↑l r
哈希表: {a:0, b:1, c:0}
最大长度: 3
步骤8:右指针移动到第四个'b'
字符串: a b c a b c b b↑ ↑l r
哈希表: {a:0, b:2, c:0}
'b'重复,移动左指针:
字符串: a b c a b c b b↑ ↑l r
哈希表: {a:0, b:1, c:0}
最大长度: 3
最终结果:最大无重复子串长度为3
时间和空间复杂度
- 时间复杂度:O(n),其中n是字符串长度。每个字符最多被访问两次(右指针遍历和左指针调整)。
- 空间复杂度:O(min(m,n)),其中m是字符集大小,n是字符串长度。哈希表最多存储min(m,n)个字符。
正确的写法
class Solution {
public:int lengthOfLongestSubstring(string s) {unordered_map<char,int> hash; //这里可以使用数组代替哈希表可以提高效率int left=0;int right=0;int ret=0;while(right < s.size()){hash[s[right]]++;while(hash[s[right]]>1){hash[s[left++]]--;}right++;ret = max(ret,right-left);}return ret;}
};