题目描述
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
题目链接: https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/
思路1
使用类似于求最大自序和的方法。设置两个指针left和right,left初始化为0,right初始化为1:
- 判断当前字符s[right]是否在字符串s的[left,right)范围内出现过:
- 如果没有出现,则将无重复子串长度加一,更新目前的无重复最长子串长度, right++;
- 如果出现了,则将left更新为[left,right)范围内与当前字符s[right]相同且离得最远的字符下标,然后加1,求目前的子串长度,然后更新目前的无重复最长子串长度;
- 重复上面的过程,直至rihgt>=s.length().
代码如下:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.empty() || s.length()==1){
return s.length();
}
int left = 0;
int right = left+1;
int maxSubStrLen = 1;
int curLen = 1;
while(right<s.length()){
int idx = find(s, left, right, s[right]);
if(idx==-1){ // s[right]在[left,right)范围内没有出现
curLen++;
right++;
maxSubStrLen = max(curLen, maxSubStrLen);
}else{ // s[right]在[left,right)范围内出现
left = idx+1; // left此时是[left,right)范围内与s[right]相等且距离最远的下标+1
right++;
curLen = right-left;
maxSubStrLen = max(curLen, maxSubStrLen);
}
}
return maxSubStrLen;
}
/*查找c是否在字符串s的[left,right)范围出现,如果出现则返回下标,否则返回-1*/
int find(string s, int left, int right, char c){
for(int i=left; i<right; i++){
if(c==s[i]){
return i;
}
}
return -1;
}
};
- 时间复杂度: O(n^2)
首先遍历一遍元素,在遍历每个元素的过程中还要查看该元素是否在前面出现过。 - 空间复杂度:O(1)
思路2
维持一个队列,该队列中不包含重复的元素,且该队列中的元素是连续的(滑动窗口)。例如字符串"abcabcbb",假设当前队列中的元素为前3个字符"abc",下一个元素为"a",在队列中出现过,则将队列最左边的元素移除,直至队列中不包含下一个元素"a",记录当前的长度和当前的最大长度。代码如下:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.empty() || s.length()==1){
return s.length();
}
unordered_set<char> lookup;
int left = 0;
int right = 0;
int maxSubStrLen =1;
while(right<s.length()){
if(lookup.find(s[right])!=lookup.end()){ // 当前元素s[right]在窗口中出现
lookup.erase(s[left]);
left++;
}else{ // 当前元素s[right]没有在窗口中出现
int curLen = right-left+1;
maxSubStrLen = max(curLen, maxSubStrLen);
lookup.insert(s[right]);
right++;
}
}
return maxSubStrLen;
}
};
- 时间复杂度: O(n)
- 空间复杂度: O(1)
虽然使用了set,但由于字符个数有限(256个),所以辅助空间的规模不会随输入规模的增大而增大,所以空间复杂度为O(1)。