题目:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
我的方法一:动态规划,O(N*N),O(N)
步骤
- 子问题
1.1 最后一步:最长子串或者包含最后一个字符,或者不包含
1.2 子问题:去除最后一个字符的字符串的最长子串的长度,和以最后一个字符为结尾的最长子串的长度谁大 - 转移方程
dp[n] = max(dp[n-1], 以最后一个字符为结尾的不重复字符的长度) - 初始条件
dp[0] = 1; - 边界条件
n<s.size() - 计算顺序
dp[0] dp[1] dp[N] - 优化点,有dp[n]只和dp[n-1]有关,所以没必要保存所有的dp,只记录当前已知最大的即可。
复杂度
时间:两层循环,所以最大是O(N*N)
空间:使用了哈希表,当所有字符都不相同时,最大是O(N)
代码
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.size() == 0){
return 0;
}
unordered_set<char> set;
const char* p_s = s.c_str();
int size = s.size();
int max_long = 0;
char tmp;
//时间O(N),空间set最大是O(N)
for(int i = 0; i < size; i++){
set.clear();
//时间最大是O(N)
for(int j = i; j >= 0; j--){
tmp = p_s[j];
if(set.find(tmp) != set.end()){
break;
}
set.insert(tmp);
}
if(max_long < set.size()){
max_long = set.size();
}
}
return max_long;
}
};
我的方法二:双指针,O(N),最大O(N)
和官方解法的滑动窗口类似,
步骤
- 快慢指针,都从第0个字符开始遍历;使用一个哈希表set存储当前以快指针为结尾的不重复字符串;
- 先判断快指针对应的字符是否在set中,如果不在,说明该字符可以加到set中,这样长度就会变长;如果字符在set中,说明存在重复的字符,这个时候移动慢指针,并将慢指针对应的字符从set中去除,直到将快指针对应的字符从set移除为止;
- 期间set的最大长度就是最终的结果
初始条件
- 快慢指针都指向第一个字符
边界条件
- 快指针遍历完了整个字符串
复杂度
时间:O(N),快指针遍历了一遍,慢指针最大遍历了一遍,所以整体是O(N)
空间:最大O(N),当所有字符都不想等时,set的长度就是字符串的长度,所以是O(N)。
代码
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.size() == 0){
return 0;
}
unordered_set<char> set;
const char* p_s = s.c_str();
int size = s.size();
int max_long = 0;
char tmp;
int left = 0;
int right = 0;
//时间复杂度是O(N),因为right和left最大都从0遍历到N
//空间复杂度最大是O(N)
while(right < size) {
if(set.find(p_s[right]) == set.end()){
set.insert(p_s[right]);
right++;
if(set.size() > max_long){
max_long = set.size();
}
}else{
set.erase(p_s[left]);
left++;
}
}
return max_long;
}
};
网友评论