题目
Given a string, find the length of the longest substring without repeating characters.
Examples:
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.
解题思路
题目要求最长的不含重复字符的子串,那么我们可以从字符串头部依次扫描,每当遇到一个未出现过的字符就把最长长度加1,当遇到一个已出现过的字符时,结束该次扫描,并保存当前最长长度,然后将扫描位置在前一次的基础上向后挪一个字符,重复上述过程,每扫描完一次,就更新最长长度,最后得到的最长长度就是该字符串的不含重复字符的子串的最长长度。
eg:“abcab” 令maxlen=0, len=0
字符 | 当前长度(len) | 最长长度(maxlen) |
---|---|---|
a | 1 | 0 |
ab | 2 | 0 |
abc | 3 | 0 |
abca | 3 | 3 |
b | 1 | 3 |
bc | 2 | 3 |
bca | 3 | 3 |
bcab | 3 | 3 |
c | 1 | 3 |
ca | 2 | 3 |
cab | 3 | 3 |
最后返回maxlen = 3。
AC代码
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int mark[256];//可能不止包含英文字符,考虑所有字符情况
memset(mark, 0, 256*sizeof(int));//初始化为0,表示该字符还未出现过
int maxlen = 0;
for(int i = 0; i < (int)s.length(); ++i)
{
int len = 0, j;
for(j = i; j < (int)s.length(); ++j)
{
if(mark[s[j]] == 0)
{
mark[s[j]] = 1;//标记该字符已出现
len++;
}
else
{
memset(mark, 0, 256*sizeof(int));
break;
}
}
maxlen = max(maxlen, len);
if(j == (int)s.length())//如果内循环已扫描到字符串尾,则直接返回
return maxlen;
}
return maxlen;
}
};
上面是比较简单的解题方法,不过时间复杂度稍稍有点高,达到了O(N²)。下面介绍一种时间复杂度在O(N)的方法。
看了上面的代码我们知道,mark数组是用来标记字符是否出现,其值为0表示未出现,为1表示已出现,那么我们是否可以用来保存在扫描过程中每个字符最后出现的位置呢?答案是肯定的,这样,每当我们遇到一个已出现的字符就更新它在mark中的值。
AC代码
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int mark[256];
memset(mark, -1, 256*sizeof(int));
int start = -1, maxlen = 0;
for(int i = 0; i < (int)s.length(); ++i)
{
if(mark[s[i]] != -1)
start = max(start, mark[s[i]]);//防止start回退
mark[s[i]] = i;
maxlen = max(maxlen, i - start);
}
return maxlen;
}
};
ps:如果是求不含重复字符的最长子序列的长度,那就更简单了,只需要求出该字符串中含有多少个不重复字符即为答案。