Given a string, find the length of the longest substring without repeating characters.
Example 1:
Input: "abcabcbb" Output: 3 Explanation: The answer is "abc", with the length of 3. Example 2:
Input: "bbbbb" Output: 1 Explanation: The answer is "b", with the length of 1. Example 3:
Input: "pwwkew" Output: 3 Explanation: 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.
解题过程很波折,开始的时候是没有想到很好的方法,后来想到了方法,但是思路有缺陷,卡在了abba这个测试用例上。
先来看下我的实现吧。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if (s.size() == 0) {
return 0;
}
int max_len = 1;
map<char, int> my_map = {};
my_map[s[0]] = 0;
for (int begin = 0, end = begin +1; end < s.size(); ){
int num = my_map[s[end]];
my_map[s[end]] = end;
auto it = my_map.find(s[end]);
if(it == my_map.end()) {
}
else {
begin = num + 1;
}
end ++;
max_len = max(max_len, end - begin) ;
}
return max_len;
}
};
对上面的代码进行修改,可以ac的版本:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if (s.size() == 0) {
return 0;
}
int max_len = 1;
map<char, int> my_map = {};
my_map[s[0]] = 0;
for (int begin = 0, end = begin +1; end < s.size(); ){
auto it = my_map.find(s[end]);
if(it != my_map.end() && begin <= my_map[s[end]]) {
begin = my_map[s[end]] + 1;
}
my_map[s[end]] = end;
end ++;
max_len = max(max_len, end - begin) ;
}
return max_len;
}
};
之前错误的思路:
比如test case "abcabcbb", 使用两个指针begin, end分别指向0,1, 然后end向后走,如果当前指向的字符在前面出现过,就将begin指针指向之前出现过位置的后面一个位置,在例子中,就是当begin = 0, end = 3的时候,发现a在前面出现过,位置是0,所以begin指针指向1,然后计算长度。但是当遇到"abba"这种case的时候,就会出现问题,end指针指向3的时候,发现字符'a'在位置0出现过,就会把begin 指针指向位置0的下一个位置,但是中间的bb是有重复的,所以应该跳过bb。
改正后的思路:
思考如何跳过"bb"呢?当重复字符的下标小于begin的时候,就说明会包含重复的部分,因为只有当有重复的字符出现的时候,begin才会往前走,begin没有后退的可能。所以,只需要添加begin <= my_map[s[end]] 判断条件就可以输出正确的结果了。
分析:
算法的时间复杂度是 O(n), 空间复杂度O(n), 其实这里还可以减小空间复杂度,或者说平均空间复杂度,这里就不在说了。