Description
Given a string, find the length of the longest substring without repeating characters.
题意
给定一个字符串,求出不带重复字符的最长子串的长度。
Example
Given "abcabcbb"
, the answer is "abc"
, which the length is 3.
Given "bbbbb"
, the answer is "b"
, with the length of 1.
Given "pwwkew"
, the answer is "wke"
, with the length of 3. Note that the answer must be a substring, "pwke"
is a subsequence and not a substring.
思路
这道题涉及查找,肯定是使用哈希表是最快的。假设Key 是字符串中的字符,Value 是长度,每次扫描时令键与当前扫描到的字符匹配,如果重复了就不加入 Map,最后输出 longth。但是这样的办法有问题,因为它求出来的是子序列而不是子串,样例3通不过,显示输出的是4。
//Note:This is Wrong Answer !!! #include<unordered_map> using std::unordered_map; class Solution { public: int lengthOfLongestSubstring(string s) { unordered_map<char,int> um; int i; int n = s.size(); int longth = 0; for (i = 0; i < n; ++i) { if (um.find(s[i]) != um.end()) { continue; } else{ um[s[i]] = ++longth; } } um.clear(); return longth; } };
随后,我再思考了一遍题目,发现其实这题可以想象成一个队列,每次入队时都需要查看队里有没有重复的字符,若有则将重复的字符及其之前的字符给删去,这样就可以保证队内没有重复的字符了。那么问题就来了,如何去模拟这样一个队列?
我们可以用1个 set 和 两个哨兵 i j 去模拟一个队列。set (集合)是一个 key 与 value 必须相等的数据结构,用它的原因是它可以用红黑树或哈希表实现,查找效率高一些。哨兵 i 表示子串左端,哨兵 j 表示子串右端,每一轮扫描都在 set 的键中查找 s[j] 是否存在,若不存在则在 set 中增加元素 s[j] 且 j++,若存在则在集合 set 中删去元素 s[i] 且 i++,这样就实现了一个队列的操作,一段出,一段入。
如何求最长子串呢?在每一轮中实时比较子串长度并更新记录 res即可。
//Runtime: 46 ms
#include<set> #include<algorithm> using std::set; using std::max; class Solution { public: int lengthOfLongestSubstring(string s) { set<char> mySet; int res = 0, temp = 0; int i = 0,j = 0; int n = s.size(); while (j < s.size()) { if (mySet.find(s[j]) != mySet.end()) { mySet.erase(s[i]); ++i; } else { mySet.insert(s[j]); ++j; } temp = mySet.size(); res = max(res, temp); } mySet.clear(); return res; } };
感觉我的方法还是有些慢,如果有更好的办法欢迎讨论。