剑指 Offer 48. 最长不含重复字符的子字符串 - 力扣(LeetCode) (leetcode-cn.com)
目录
解法1:滑动窗口
运行结果
思路
设置一个窗口,窗口中的所有字符均不相重复,维护窗口的leftSide和rightSide。leftSide和rightSide初始化均为0,每次扩展窗口的rightSide(++rightSide),并检测rightSide位置的字符:
1. 如果和窗口中的任意字符均不重复,那么直接将rightSide位置的字符纳入窗口;
2. 如果和窗口中pos位置的字符重复了,那么更新窗口:leftSide = pos + 1,把pos及之前位置的字符均从窗口中排除掉,把rightSide位置的字符纳入窗口。
设置一个数组pos来记录窗口中每个字符在字符串中的位置,ASCII码总共只有128个,就算每个字符都在字符串中出现,记录它们的位置也不过128 * 4B即0.5KB,空间开销不大,因此完全可以开一个长度为128的数组。
rightSide位置的字符出现在窗口中(和某个位置的字符重复):pos[s[rightSide]] >= leftSide;
把rightSide位置的字符纳入窗口:pos[s[rightSide]] = rightSide;
代码
class Solution {
#define scale 0x7f
public:
int lengthOfLongestSubstring(string s) {
int pos[scale];
for (int i = 0; i != scale; ++i) pos[i] = -1;
int L = s.length();
int leftSide = 0, len, max_len = 0;
for (int rightSide = 0; rightSide != L; ++rightSide) {
if (pos[s[rightSide]] >= leftSide) {
len = rightSide - leftSide;
len > max_len ? max_len = len : NULL;
leftSide = pos[s[rightSide]] + 1;
}
pos[s[rightSide]] = rightSide;
}
return max(max_len, L - leftSide);
}
};
解法2:动态规划
运行结果
思路
我们用len[i]来表示以s[i]为结尾的最长不重复子串的最大长度,考虑len[i]和len[i-1]的关系。如果s[i]没有在以s[i-1]为结尾的最长不重复子串中出现,那么len[i] = len[i-1] + 1;如果s[i]出现在了以s[i-1]为结尾的最长不重复子串中,那么len[i] = 两个重复字符之间的距离。
使用一个数组pos来记录各个字符上次在字符串中出现的位置,数组元素初始化为-1.
代码
class Solution {
#define scale 0x7f
public:
int lengthOfLongestSubstring(string s) {
int pos[scale];
for (int i = 0; i != scale; ++i) pos[i] = -1;
int L = s.length();
int len = 0, max_len = 0;
for (int i = 0; i != L; ++i) {
int d = i - pos[s[i]];
len = d > len ? len + 1 : (len > max_len ? max_len = len : NULL, d);
pos[s[i]] = i;
}
return max(len, max_len);
}
};