力扣 3. 无重复字符的最长子串-爱代码爱编程
一、题目
(链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/)
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
提示:
- 0 <= s.length <= 5 * 104
- s 由英文字母、数字、符号和空格组成
二、分析
- 子串是连续的,就跟子数组一样,而子序列是可以不用连续的。
- 用双指针算法来解决,枚举出所有可能出现的情况,再从无重复的子串中取最大值即可。max可以边枚举边更新。
- 如果now将一个重复的字符纳入子串,那纳入的这个字符一定是重复字符,只需要将这个重复的字符挤出子串,并在这个过程中,将挤出的字符对应的map值进行清零即可。如下图所示:
三、代码示例
C++版本
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int max = 0;
unordered_map<char, int> m;
for(int now = 0, last = 0; now < s.size(); now++) { // 通过now遍历所有字符,并以last来辅助截取无重复的子串,从而枚举出所有不重复的子串
m[s[now]]++; // now每指向一个新的字符,这个字符就算是进入了当前子串,所以要进行统计+1
while(m[s[now]] > 1) { // 去重(将重复字符挤出子串前,会一直循环,并且把循环过程中的map值清零,因为后面就是要重新计算一个子串了,跟原先子串就无关系了)
m[s[last]]--; // 先清除当前位置的map值
last++; // last再往后移动
}
if (max < now - last + 1) { // 边遍历边更新max
max = now - last + 1;
}
}
return max;
}
};
Golang版本
func lengthOfLongestSubstring(s string) int {
last := 0
max := 0
m := make(map[byte]int)
for now := 0; now < len(s); now++ {
m[s[now]]++
for m[s[now]] > 1 {
m[s[last]] --
last++
}
if max < now - last + 1 {
max = now - last + 1
}
}
return max
}