请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
直接暴力,超时了
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.length() == 0) return 0;
int res = 1;
int head = 0;
int count = 1;
int flag = 0;
for(int i = 1; i < s.length(); i++){
cout << i << ' '<<count<<endl;
for(int j = head; j < i; j ++){
if(s[i] == s[j]){
//cout << i <<' ' << j << endl;
head += 1;
i = head;//这里不加一是因为后面还有个i++
count = 1;
flag = 1;
break;
}
}
if(flag == 0){
count++;
if(count > res) res = count;
}
else{
flag = 0;
}
//cout << i << ' '<<count<<' '<<s.length()<<endl;
}
return res;
}
};
动态规划法
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.size() == 0) return 0;
int dp[s.size()+1];//dp[i]表示以i为结尾的最长不重复子串长度
dp[0]=1;
int maxlen = 1;
for(int i = 1; i < s.size(); i++){
int distance = INT_MAX;//与s[i]相同的字符距离s[i]有多远
for(int j = i-1; j >= 0; j --){
if(s[j] == s[i]){
distance = i - j;
break;
}
}
if(distance > dp[i-1]){//如果sj在子串之外,那么就是dp[i-1]加上si
dp[i] = dp[i-1]+1;
}
else{//如果sj在子串之内,那么子串从j+1开始直到i
dp[i] = distance;
}
if(dp[i] > maxlen) maxlen = dp[i];
}
return maxlen;
}
};
这里可以用一个变量代替dp节约空间,可以用哈希表存储每个数最后出现的位置来改进
暴力法时间复杂度是ON3,dp的时间复杂度是ON2,利用哈希表是O1
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
dic = {}
res = tmp = 0
for j in range(len(s)):
i = dic.get(s[j], -1) # 获取索引 i
dic[s[j]] = j # 更新哈希表
tmp = tmp + 1 if tmp < j - i else j - i # dp[j - 1] -> dp[j]
res = max(res, tmp) # max(dp[j - 1], dp[j])
return res