题目
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
解析
方法一:map+queue
关于这个题目最简单的思路就是暴力求解,但是这种方法效率很低,不是解决算法问题的首选。后来我想到根据题目的特殊要求运用合适的数据结构解决问题。
最先想到的是map,因为想要判断字符是否重复map中提供两个方法,一个是find(key),返回迭代器。另一个是count(key)返回的是0或1。将string中每个字符添加到map里面便于寻找是否有重复字符。
其次就是当遇到重复字符的处理,我的思路是当遇到重复字符时需要将和当前子串中从字符头部开始一直到和当前字符相同的元素都删除,比如对字符abcdbcd字符串求无重复最长子串时当处理到字符b时发现此时字符重复,则应该将子串中的字符ab删除后继续进行下一步操作。删除时需要秉持先进先出的原则,因此使用queue数据结构进行操作。
实现代码
int lengthOfLongestSubstring(string s)
{
map<char, char>maps;
queue<char> q;
int max(0), i(0);
while (i < s.size())
{
if (maps.count(s[i]))//当出现重复字符时
{
if (max < q.size())//若此时字符串长度大于最大字符串长度,则更新子字符串长度
{
max = q.size();
}
while (q.front() != s[i])//删除队列和map里重复字符及在重复字符之前进来的字符
{
maps.erase(q.front());
q.pop();
}
maps.erase(q.front());
q.pop();
}
else
{
maps.insert(pair<char, char>(s[i], s[i]));
q.push(s[i]);
i++;
//tager++;
}
}
if (max < q.size())//最后还需要再判断一次最优解
{
max = q.size();
}
return max;
}
方法二:sliding window
提取题目中的关键词:给定一个字符串 s ,请你找出其中不含有重复字符
的 最长
子串
的长度
我们可以发现,该算法题求的结果是最长子串,需满足的条件是不含有重复字符。这是一道典型的滑动窗口(sliding window)算法问题,可以用滑动窗口算法解决。关于滑动窗口类算法的讲解可以看我的Leetcode算法总结–滑动窗口类算法解析这一篇博客。
实现代码
int lengthOfLongestSubstring(string s)
{
int left(0);
int bestresult(0);
unordered_set<char> v;
for (int i = 0; i < s.size(); i++)
{
while (v.find(s[i]) != v.end())//不满足题目条件时
{
v.erase(s[left]);//滑动窗口收缩
left++;
}
v.insert(s[i]);//字符不重复时(满足条件)滑动窗口向右扩张
bestresult = max(bestresult, i-left+1);
}
return bestresult;
}