题目要求:给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
方法一:暴力法 时间复杂度O(n^3) 空间复杂度O(min(m, n)) 超出时间限制
思路:
【1】以长度length为for循环进行截取字符串 for(int i=length;i>0;i--)
【2】对于截取的字符串进行判断,若无重复字符则返回当前长度
//判断字符串有无重复部分
bool isRepeat(string str) {
set<char> s;
for (int i = 0;i < str.length();++i) {
char ch = str[i];
//有重复部分
if (s.find(ch) != s.end()) {
return true;
}
s.insert(ch);
}
return false;
}
int lengthOfLongestSubstring(string s) {
int length; //截取长度
for (length = s.length();length > 0;length--) {
//index为截取开始位置
for (int index = 0;index <= s.length() - length;++index) {
string str = s.substr(index, length);
if (!isRepeat(str)) {
return length;
}
}
}
return 0;
}
方法二:滑动窗口 时间复杂度O(n),空间复杂度O(min(m, n))//n为字符串的大小,m为字符集的大小
思路:
【1】如果从索引 i 到 j - 1 之间的子字符串 s(i,j-1) 已经被检查为没有重复字符。我们只需要检查 s_j 对应的字符是否已经存在于子字符串 s(i,j-1) 中。
【2】用hashMap记录字符及其下标,未出现重复字符则将其添加到hashMap中。
【3】若出现重复字符则计算开始位置begin的下标,当前长度currLen为index-begin+1。并更新重复字符的下标
int lengthOfLongestSubstring(string s) {
if (s.length() <= 1)
return s.length();
unordered_map<char, int> hashMap;
int max = -1, begin = 0, index = 0, currLen = 0; //begin为无重复字符串开始位置
for (;index < s.length();++index) {
char ch = s[index];
//未出现重复的字符
if (hashMap.find(ch) == hashMap.end()) {
hashMap.insert({ ch,index });
}
else {
int temp = hashMap[ch]+1; //出现重复字符的下一个下标
begin = begin > temp ? begin : temp; //开始位置为较大的位置
hashMap[ch] = index;
}
currLen = index - begin + 1; //现有长度
max = max > currLen ? max : currLen;
}
return max;
}
对于开始位置begin选择较大位置的说明
例:字符串"twswqpt",当遍历到第二个w时,begin将等于重复字符下一个字符的下标,即s的下标(2)。begin=2
之后遍历到第二个t时,如果没有选择较大位置的begin,begin将等于第一个t后一个字符的下标,即第一个w的下标(1),
显然这是错误的,因为begin等于1的话,字符串中w就重复了。所以要比较begin和temp的大小,选择较大的位置。
最后贴出leetcode中关于本题的讲解
https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/