3. Longest Substring Without Repeating Characters
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.
class Solution {
public:
int lengthOfLongestSubstring(string s) {
}
};
解题思路:
-
自己的解题思路
运用动态规划进行求解。
dp[i]
是指字符串从头到
s[i]
所找到的最长无重复子字符串长度。因此,答案
dp[s.size()-1]
就是所要的结果。期间用到了辅助数组标记访问位。
时间复杂度为
O(n*n)
。
-
别人的解题思路
通过增加一个
start
来记录当前子字符串的起始位置,利用辅助数组来记录字符上次出现的位置(这里有两种方法:方法
1
,考虑所有
128
个字符;方法
2
,利用
map,
可以只记录出现的字符)。
时间复杂度为
O(n*n)
。
学习收获:
-
最近练的题目难度开始上升。有种无法总结的感觉,可能相关题目练的比较少。
-
fill ( last , last + ASCII_MAX , - 1 ); 新语法 fill() 。
-
map<char,int> charMap;
charMap.count(s[i])==0;
熟悉了
map
里面的
count()
附件:程序
1
、自己的程序:
int
flag
[
128
]
=
{
0
};
int
getMax
(
int
x
,
int
y
)
{
return
x
>
y
?
x
:
y
;
}
void
init
(
int
*
flag
,
int
num
)
{
for
(
int
i
=
0
;
i
!=
num
;
++
i
)
{
flag
[
i
]
=
0
;
}
}
class
Solution
{
public
:
int
lengthOfLongestSubstring
(
string
s
)
{
if
(
s
.
size
()
==
0
)
{
return
0
;
}
vector
<
int
>
dp
(
s
.
size
(),
1
);
for
(
int
i
=
1
;
i
!=
s
.
size
();
++
i
)
{
int
j
=
i
;
int
len
=
0
;
//向前开始查找,找到以s[i]结尾的最长无重复子序列
for
(;
(
j
>=
0
)
&&
(
flag
[
s
[
j
]]
==
0
);
--
j
)
{
flag
[
s
[
j
]]
=
1
;
++
len
;
}
dp
[
i
]
=
getMax
(
dp
[
i
-
1
],
len
);
init
(
flag
,
128
);
}
return
dp
[
s
.
size
()
-
1
];
}
};
2
、别人的程序
版本
1
:使用了
map
class
Solution
{
public
:
int
lengthOfLongestSubstring
(
string
s
)
{
map
<
char
,
int
>
charMap
;
int
start
=
-
1
;
int
maxLen
=
0
;
for
(
int
i
=
0
;
i
<
s
.
size
();
i
++)
{
if
(
charMap
.
count
(
s
[
i
])
!=
0
)
{
//更新开始位置,max()不能少
start
=
max
(
charMap
[
s
[
i
]],
start
);
}
charMap
[
s
[
i
]]
=
i
;
maxLen
=
max
(
maxLen
,
i
-
start
);
}
return
maxLen
;
}
};
版本
2
,直接有点类似暴力,枚举出所有
char
取值
int
lengthOfLongestSubstring
(
string
s
)
{
vector
<
int
>
dict
(
256
,
-
1
);
int
maxLen
=
0
,
start
=
-
1
;
for
(
int
i
=
0
;
i
!=
s
.
length
();
i
++)
{
if
(
dict
[
s
[
i
]]
>
start
)
start
=
dict
[
s
[
i
]];
dict
[
s
[
i
]]
=
i
;
maxLen
=
max
(
maxLen
,
i
-
start
);
}
return
maxLen
;
}
版本
2
变形,比较两个版本,注意细节差异。
class
Solution
{
public
:
int
lengthOfLongestSubstring
(
string
s
)
{
const
int
ASCII_MAX
=
255
;
int
last
[
ASCII_MAX
];
int
start
=
0
;
fill
(
last
,
last
+
ASCII_MAX
,
-
1
);
int
max_len
=
0
;
for
(
int
i
=
0
;
i
<
s
.
size
();
i
++)
{
if
(
last
[
s
[
i
]]
>=
start
)
{
max_len
=
max
(
i
-
start
,
max_len
);
start
=
last
[
s
[
i
]]
+
1
;
}
last
[
s
[
i
]]
=
i
;
}
return
max
((
int
)
s
.
size
()
-
start
,
max_len
);
};
这个思路很简单,就是建个临时
str
,来存储当前遍历到的无重复子序列;再利用
string
的
find()
进行查找。
但是,不知道为什么这个程序效率比上面的程序高。感觉效率不是很高。因为有
find(),erase()
这样可能
O(n)
的操作。
class
Solution
{
public
:
int
lengthOfLongestSubstring
(
string
s
)
{
int
length
=
0
,
cur
=
0
;
string
str
;
for
(
int
i
=
0
;
i
<
s
.
size
();
++
i
)
{
int
pos
=
str
.
find
(
s
[
i
]);
if
(
pos
!=
string
::
npos
)
{
length
=
max
(
length
,
(
int
)
str
.
size
());
str
.
erase
(
str
.
begin
(),
str
.
begin
()
+
pos
+
1
);
}
str
.
push_back
(
s
[
i
]);
}
return
max
(
length
,
(
int
)
str
.
size
());
}
};