为了能到远方,脚下的每一步都不能少.|

顾子郤

园龄:11个月粉丝:5关注:2

3. 无重复字符的最长子串

题目描述

给定一个字符串 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 由英文字母、数字、符号和空格组成

题解

思路:从第一个字符开始,不断扩大子串。如果出现重复,则从重复的字符处重新开始扩大子串。

滑动窗口

  • 哈希表存储字符,用于判断是否有重复字符出现。

存在问题:算法执行时间非常长(大于600 ms)

可能原因:

  1. 哈希表被反复清空
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> umap;
int len = 0;
int max = 0;
for (int i = 0; i < s.length(); i++) {
if (umap.find(s[i]) == umap.end()) {
umap.insert({s[i], len++});
} else {
umap.clear();
max = max > len ? max : len;
i-=len; // 从失败的字符重新开始匹配。
len = 0;
}
}
max = max > len ? max : len; // 处理最长子串在结尾的情况
return max;
}
};

[!NOTE]

unordered_map插入的顺序是{value,index}find查找的时候,查找value值。如果找到,则返回key键;如果没有找到,则返回.end()末尾。

滑动窗口优化

此解法参考Krahets。耗费时间10 ms,速度提升近60倍。因此,哈希表的清空.clear()是一个非常耗费时间的过程。

核心思想:避免清空哈希表,保持哈希表内元素下标最新。

class Solution {
public:
int lengthOfLongestSubstringImproved(string s) {
unordered_map<char, int> umap;
int left = -1, len = 0, maxLen; // left:最长无重复字符子串的最右端。起始情况最长字符为空,所以left为-1
for (int right = 0; right < s.size(); right++) { // right:指向被判断的字符
if (umap.find(s[right]) != umap.end()) // 在哈希表中,被查找到
left = max(left, umap.find(s[right])->second); // 更新左指针。反例abba,足以解释为什么要用max
umap[s[right]] = right; // 哈希表记录。保持哈希表中的元素始终是不重复的,且坐标都是最新的,相当于窗口在滑动
maxLen = max(len, right - left); // 更新结果
}
return maxLen;
}
};

难理解点

  1. left = max(left, umap.find(s[right])->second)

举例,输入字符串abba。

当right指向第二个b时,出现重复。此时,left = -1umap.find(s[right])->second) = 2。left就直接移动到了第二个b的位置,即从重复字符开始重新匹配。注意,此时哈希表中的a的下标仍然是0。

当right指向第二个a时,出现重复。此时,left = 2umap.find(s[right])->second) = 0,即重复字符不是left指向的字符,此时left就不想要移动。

  1. umap[s[right]] = right

该方式:

  • 如果键值对不存在,则插入
  • 如果键值对存在,则修改值对应的键
  1. maxLen = max(len, right - left)

求两个范围内的个数,一般情况下需要+1,即其中一个端点。

但是,理清left和right的含义。left:最长无重复字符子串的最右端;right:被判断的字符,即最长不重复子串的在一个,相当于已经+1了。

本文作者:顾子郤

本文链接:https://www.cnblogs.com/coder-shane/p/18441581

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   顾子郤  阅读(12)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起