This commit is contained in:
ShusenTang 2020-02-11 17:33:07 +08:00
parent 84e7d504b4
commit 7c97295f36

View File

@ -3,18 +3,24 @@
## 思路一、暴力动归
用一个与s等长数组dp记录以某个字符结尾的最长不重复子串的长度即`dp[i] = m`表示以s[i]结尾的最长不重复子串的长度为m。所以dp初始化全为1.
dp[i]应该这样计算:
* 从s[i-1]开始往前遍历dp[i-1]个字符若中途遍历到某个字符与s[i]相等了则跳出循环。若往前遍历了tmp(从0开始)个字符,则`dp[i] += tmp`。
* 从s[i-1]开始往前遍历dp[i-1]个字符若中途遍历到某个字符与s[i]相等了则跳出循环。若往前遍历了tmp(从0开始)个字符,则`dp[i] = 1 + tmp`。
时间复杂度O(n*n)空间复杂度O(n)
由于计算dp[i]时只用到了前一个dp[i-1]所以可采用滚动数组的方式将空间优化至O(1)
时间复杂度O(n*n)空间复杂度O(1)
## 思路二、窗口法
用一个hash map(这里直接用一个长为128数组就行了因为ASCII就是0-127) mp记录某个字符c在s中的位置初始全-1.
用left、i记录当前窗口左、右边的位置窗口[left ~ i]中保证是无重复的。
left和i初始都为0i从0开始不断加1并按下面步骤循环:
1. 设当前字符为c`mp[c] >= left`则字符c第二次出现在了窗口中left即将右移先更新res再将left移动到上一个c的下一个位置;否则什么都不做。
2. 最后更新mp: ` mp[c] = i`
用left、right记录当前窗口左、右边的位置窗口[left ~ right]中保证是无重复的。
时间复杂度O(n)空间复杂度O(1)
left和right初始都为0right从0开始不断加1并按下面步骤循环:
* 设当前字符为c
1. 若 `mp[c] >= left`则字符c第二次出现在了窗口中将left更新到上一个c所在位置的下一个位置;
2. 还要更新` mp[c] = right`以及res。
由于两个指针从左到右都只遍历了一次所以时间复杂度O(n)空间复杂度O(1)
值得一提的是mp的作用就是记录 c 是否已经在窗口内所以也可以用一个set把出现过的字符都放入其中如果遇到重复的则从左边开始删字符直到删到重复的字符。
# C++
## 思路一
@ -22,16 +28,14 @@ left和i初始都为0i从0开始不断加1并按下面步骤循环:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.size() == 0) return 0;
vector<int>dp(s.size(), 1);
int res = 1;
if(s.empty()) return 0;
int dp = 1, res = 1, tmp;
for(int i = 1; i < s.size(); i++){
int tmp = 0;
for(; tmp < dp[i - 1]; tmp++){ // 往前遍历dp[i - 1]个字符
for(tmp = 0; tmp < dp; tmp++) // 往前遍历dp[i - 1]个字符
if(s[i] == s[i - 1 - tmp]) break;
}
dp[i] = dp[i] + tmp;
res = (dp[i] > res ? dp[i]:res);
dp = 1 + tmp;
res = max(res, dp);
}
return res;
}
@ -42,17 +46,19 @@ public:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
vector<int>mp(128, -1); // 记录s中某个字符所在位置初始为-1 (数组大小设置成256貌似快一些不知道为啥)
int left = 0, res = 0, i = 0; // 窗口[left ~ i]中保证是无重复的
for(; i < s.size(); i++){
char c = s[i];
if(mp[c] >= left) { // 字符c第二次出现在了窗口中left即将右移先更新res
res = max(res, i - left);
left = mp[c] + 1; // left右移到上一个c所在位置的下一个位置
vector<int>mp(128, -1); // 记录s中某个字符所在位置初始为-1
int left = 0, right = 0, res = 0; // 窗口[left~right]中保证是无重复的
char c;
for(; right < s.size(); right++){
c = s[right];
if(mp[c] >= left) // 字符c第二次出现在了窗口中, 更新left
left = mp[c] + 1; // 更新到上一个c所在位置的下一个位置
mp[c] = right;
res = max(res, right - left + 1);
}
mp[c] = i; // 当前字符c的位置
}
return max(res, i - left);
return res;
}
};
```