题目描述:

题目描述如下

题解一:

首先想到一个暴力的方法,考虑所有的子串。比如一个字符串的长度是n,那么它有1个长度为n的子串,2个长度为n-1的子串,…,n个长度为1的子串。从长到短遍历,对于每个子串判断其是否包含重复元素(这个比较简单),一旦找到长度为x的不重复的子串,就可以返回长度x了。

时间复杂度是O(n3),长度遍历一层循环、特定长度子串遍历一层循环、判断是否重复一层循环。

这个方法是正确的,但是不能ac。因为太慢了,最长的一个测试样例时间超限。

源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Solution {
public:
//判断一个字符串是否存在某个字符
bool ifExist(char* arr,int count, char c){
for(int i=0;i<count;i++){
if(arr[i] == c){
return true;
}
}
return false;
}
//判断一个字符串是否含有重复字符
bool ifRe(char* s, int len){
char arr[200];
int count = 0;
for(int i=0;i<len;i++){
if(ifExist(arr, count, s[i])){
return true;
}
arr[count] = s[i];
count++;
}
return false;
}
int lengthOfLongestSubstring(string s) {
int len = s.length();
for(int i=len;i>=1;i--){
int nums = len - i + 1; //i长度得子串数目
for(int j=0;j<nums;j++){
char temp[50000];
for(int k=j;k<(j+i);k++){
temp[k-j] = s[k];
}
if(!ifRe(temp, i)){
return i;
}
}
}
return 0;
}
};

题解二:

只好选择时间复杂度更为优化的算法。

想到,遍历字符串的每个字符,所有的子串一定是以其中某个字符开头的连续序列。那么我们把每个字符开头的最长连续子串长度算出,再取其中的max即可。

对于每个字符,逐个取其后的字符,如果没有重复就加入子串,直到出现重复,从而计算出最长长度。

源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Solution {
public:
//判断一个字符串是否存在某个字符
bool ifExist(char* arr,int count, char c){
for(int i=0;i<count;i++){
if(arr[i] == c){
return true;
}
}
return false;
}
int lengthOfLongestSubstring(string s) {
int len = s.length();
int* max;
max = new int[len];
for (int i = 0; i < len; i++)
{
char start = s[i];
char temp[50000];
temp[0] = start;
int maxlen = 1;
for (int j = i+1; j < len; j++)
{
if(ifExist(temp, maxlen, s[j])){
break;
}
temp[maxlen] = s[j];
maxlen += 1;
}
max[i] = maxlen;
}
int result = 0;
for (int i = 0; i < len; i++)
{
if(max[i] > result){
result = max[i];
}
}
return result;
}
};

这个算法已经可以通过测试了,但是时间复杂度不算好,O(n2)。

题解三:

在题解二的基础上进一步优化。

实际上题解二是有重复计算的部分的:对于第k个字符,其最长不重复子串可能到第rk个字符。那么我们继续计算k+1个字符的最长不重复子串时,k+1到rk的字符子串是不会重复的,完全可以避免判断,直接从rk之后开始。所以只需要维护一个变量last,记录上一个字符最后的索引,下一次直接从last+1开始考虑,前面照搬即可。

源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Solution {
public:
//判断一个字符串是否存在某个字符
bool ifExist(char* arr,int count, char c){
for(int i=0;i<count;i++){
if(arr[i] == c){
return true;
}
}
return false;
}
int lengthOfLongestSubstring(string s) {
int len = s.length();
int* max;
max = new int[len];
int last = 0;
for (int i = 0; i < len; i++)
{
char temp[50000];
for(int j=i;j<=last;j++){
temp[j-i] = s[j];
}
int maxlen = last - i + 1;
for (int j = last+1; j < len; j++)
{
if(ifExist(temp, maxlen, s[j])){
break;
}
temp[maxlen] = s[j];
maxlen += 1;
}
max[i] = maxlen;
last = i + maxlen - 1;
}
int result = 0;
for (int i = 0; i < len; i++)
{
if(max[i] > result){
result = max[i];
}
}
return result;
}
};

虽然时间复杂度还是O(n2),但是一定比上一个方法快。

以上。