原题:
3. 无重复字符的最长子串
4. 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
示例 4:
输入: s = “”
输出: 0
解答:
使用双指针滑窗的方法,剔除最左侧char,直到无重复元素。
乍一看思路,觉得deque最方便,但实际上考虑判断重复元素,使用哈希的unordered_set查找最高效,但空间复杂度稍高,deque的思想则自行通过下标指针left, right对set插入( lookup.insert(s[i]) )和删除( lookup.erase(s[left]) )实现。
注:
unordered_set基于哈希表,是无序的。
set实现了红黑树的平衡二叉检索树的数据结构,有排序,但其查找效率一般,且空间复杂度高。
容器 | 时间复杂度 | 空间复杂度 |
---|---|---|
unordered_set | 36 ms | 10.6 MB |
set | 52 ms | 13.2 MB |
deque | 56 ms | 7.7 MB |
// unordered_set源码:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.size() == 0) return 0;
unordered_set<char> lookup;
int maxStr = 0;
int left = 0;
for(int i = 0; i < s.size(); i++){
while (lookup.find(s[i]) != lookup.end()){
lookup.erase(s[left]);
left ++;
}
maxStr = max(maxStr,i-left+1);
lookup.insert(s[i]);
}
return maxStr;
}
};
// deque源码:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unsigned int max_len = 0;
deque<char> substr;
int rp = 0;
while(rp < s.size()) {
if (find(substr.begin(), substr.end(),s[rp]) == substr.end()) {
substr.push_back(s[rp]);
rp++;
} else {
substr.pop_front();
}
max_len = max_len>substr.size() ? max_len : substr.size();
}
return max_len;
}
};
扩展:
// set, unordered_set查找重复的方法:
unordered_set<char> set_;
set_.count('a') > 0; // >0可省略不写
set_.find('a') != set_.end();
// vector, deque查找重复的方法
vector<char> vec;
auto it = find(vec.begin(), vec.end(), 'a');
it != vec.end(); // find需要include<algorithm>
// unordered_multiset和set一致,使用.count('a')即可