LeetCode/solutions/3. Longest Substring Without Repeating Characters.md

59 lines
2.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# [3. Longest Substring Without Repeating Characters](https://leetcode.com/problems/longest-substring-without-repeating-characters/)
# 思路
## 思路一、暴力动归
用一个与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`。
时间复杂度O(n*n)空间复杂度O(n)
## 思路二、窗口法
用一个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`
时间复杂度O(n)空间复杂度O(1)
# C++
## 思路一
``` C++
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.size() == 0) return 0;
vector<int>dp(s.size(), 1);
int res = 1;
for(int i = 1; i < s.size(); i++){
int tmp = 0;
for(; tmp < dp[i - 1]; tmp++){ // 往前遍历dp[i - 1]个字符
if(s[i] == s[i - 1 - tmp]) break;
}
dp[i] = dp[i] + tmp;
res = (dp[i] > res ? dp[i]:res);
}
return res;
}
};
```
## 思路二
``` C++
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所在位置的下一个位置
}
mp[c] = i; // 当前字符c的位置
}
return max(res, i - left);
}
};
```