问题链接
题目解析
求字符串的最长无重复子串。
解题思路
第一个问题是子串,注意是连续的。
建立一个符号哈希数组 (in[256]),代表该符号时候出现过,256大小是因为ASCII表共能表示256个字符。初始化为0,代表未出现,当 (in[i] > 0) 时,表示该字符最近出现的索引位置+1。
定义变量(res):记录最长无重复子串长度;(left):包含当前字符的最长无重复子串的起始位置。遍历字符串,遇到未出现的字符((in[s[i]] == 0))时,更新 (res);注意另一种情况,当哈希表中的值小于 (left),原因是出现过重复的字符,导致 (left) 的位置更新了(变大),如果又遇到了新的字符或者虽然重复,但重复位置在 (left) 之前,也需要更新 (res)。否则的话,就要更新 (left) 的位置为 (in[s[i]])。
(left) 更新问题:注意理解更新 (left) 的条件,一方面理解:无法更新 (res),就要更新 (left),二者是对立的;另一方面,直接理解更新条件:(in[s[i]] > 0 && in[s[i]] >= left)。在当前字符重复的情况下,且重复位置在 (left) 的右边时,更新 (left)。
注意每次都需要更新 (in[s[i]] = i+1),目的是下次再遇到此字符时,直接将 (left) 赋值为 (in[s[i]]),保证无重复。
参考代码
class Solution {
public:
int lengthOfLongestSubstring(string s) {
vector<int> in(256, 0);
int res = 0, left = 0;
for (int i = 0; i < s.size(); i++) {
if (in[s[i]] == 0 || in[s[i]] < left) {
res = max(res, i-left+1);
}
else
left = in[s[i]];
in[s[i]] = i+1;
}
return res;
}
};
思路一样,有一种更精简的写法。(res) 和 (left) 的定义不变,(in[s[i]]) 的值稍微变化,变为字符最近出现的索引位置,没有+1。
先更新 (left),再更新 (in[s[i]]),最后更新 (res),妙不可言~
class Solution {
public:
int lengthOfLongestSubstring(string s) {
vector<int> in(256, -1);
int res = 0, left = -1;
for (int i = 0; i < s.size(); ++i) {
left = max(left, in[s[i]]);
in[s[i]] = i;
res = max(res, i - left);
}
return res;
}
};
解法二:set
运用集合(set),其特点是不包含重复元素。思路其实还是没有变,遍历字符串,把未出现过的字符都放入set中,更新结果res;如果遇到重复字符,则从左边开始删字符,直到删到集合中没有重复的字符停止。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
set<char> t;
int res = 0, left = 0, right = 0;
while (right < s.size()) {
if (t.find(s[right]) == t.end()) {
t.insert(s[right++]);
res = max(res, (int)t.size());
} else {
t.erase(s[left++]);
}
}
return res;
}
};
LeetCode All in One题解汇总(持续更新中...)
本文版权归作者AlvinZH和博客园所有,欢迎转载和商用,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.