给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
示例 4:
输入: s = “”
输出: 0
提示:
0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成
暴力求解
当检测到子串中拥有相同的字符时,我们应该更新start值,我们找出相同字符的位置用变量 j 保存,讲start更新为 j+1
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s=="")
{
return 0;
}
int start = 0, max = 0,j=0;
for (int i = 0; i < s.length(); i++){
int flat = 0;
for (j = start; j < i; j++){
if (s[i] == s[j]){
flat = 1;
break;
}
}
if (flat == 1){
start = j + 1;
}
if (max < (i - start)){
max = i - start;
}
}
return max + 1;
}
};
哈希表
哈希表就是一种映射,我们使用unordered_map实现映射功能语句 m[s[i]]=i 记录字符中对应在字符串中的序号语句 m.find(s[i])!=m.end() 用来查找新的字符在字符串中是否存在,值得注意的是判断中m[s[i]]>=start 这句话非常关键,例如 s=“abba” ,当我们识别到第二个a的时候,我们会发现start 更新后等于 1 ,这时候 i=3 那么 max=3 这是不合理的,关键在于 start 的值变小了,无论如何 start 的值是不会后退的。
class Solution {
public:
int lengthOfLongestSubstring(string s)
{
if (s == "")
{
return 0;
}
int start = 0, max = 0;
unordered_map<char, int>m;
for (int i = 0; i < s.length(); i++)
{
if (m.find(s[i]) != m.end()&&m[s[i]]>=start)
{
start = m[s[i]]+1;
}
m[s[i]] = i;
if (max < (i - start))
{
max = i - start;
}
}
return max+1;
}
};
使用桶
使用桶来代替哈希表的查找大大提高了运行时间,使用 t[s[i]]=i 语句保存字符相应在字符中的序列,但是依然需要加一个判断并且,由于字符在字符串中是存在的,那么 t[s[i]]>0,这又恰好大于 start 值,所以我们将 t[s[i]]>0&&t[s[i]]>=start 两句话合并成一句就够了
这里为什么 t[s[i]] = i+1 使其从一开始算起,因为我们初始化桶的时候初始值为零,这样当输入为单符号的时候会出现长度为零的情况,所以我们从开始算起。
class Solution {
public:
int lengthOfLongestSubstring(string s)
{
if (s == "")
{
return 0;
}
int start = 0, max = 0;
int t[256] = { 0 };
for (int i = 0; i < s.length(); i++) {
if (t[s[i]]>=start)
{
start = t[s[i]];
}
t[s[i]] = i+1;
if (max < (i - start)) {
max = i - start;
}
}
return max+1;
}
};