剑指 Offer II 016. 不含重复字符的最长子字符串
题目描述
给定一个字符串 s
,请你找出其中不含有重复字符的 最长连续子字符串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子字符串是 "abc",所以其
长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子字符串是 "b"
,所以其长度为 1。
示例 3:
输入: s = "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是"wke"
,所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke"
是一个子序列,不是子串。
示例 4:
输入: s = "" 输出: 0
提示:
0 <= s.length <= 5 * 104
s
由英文字母、数字、符号和空格组成
注意:本题与主站 3 题相同: https://leetcode.cn/problems/longest-substring-without-repeating-characters/
解法
方法一:双指针 + 哈希表
我们用两个指针 $j$ 和 $i$ 维护一个不包含重复字符的子串,其中 $j$ 为子串的左边界,$i$ 为子串的右边界,用一个哈希表或数组 $ss$ 记录窗口中所有出现过的字符。
接下来,我们遍历字符串 $s$,对于当前遍历到的字符 $s[i]$,如果 $s[i]$ 在 $[j, i)$ 范围内有与 $s[i]$ 相同的字符,我们就不断地向右移动指针 $j$,直到 $ss[s[i]]$ 为 false
,此时 $[j,i)$ 中没有任何与 $s[i]$ 相同的字符,我们就找到了以字符 $s[i]$ 为结尾的最长子串。对于每个 $i$,我们都更新最长子串的长度,最终返回答案。
时间复杂度 $O(n)$,空间复杂度 $O(|\Sigma|)$,其中 $n$ 为字符串 $s$ 的长度,而 $\Sigma$ 表示字符集,本题中字符集为所有 ASCII 码在 $[0, 128)$ 内的字符,即 $|\Sigma|=128$。
Python3
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
ss = set()
ans = j = 0
for i, c in enumerate(s):
while c in ss:
ss.remove(s[j])
j += 1
ans = max(ans, i - j + 1)
ss.add(c)
return ans
Java
class Solution {
public int lengthOfLongestSubstring(String s) {
boolean[] ss = new boolean[128];
int ans = 0, j = 0;
int n = s.length();
for (int i = 0; i < n; ++i) {
char c = s.charAt(i);
while (ss[c]) {
ss[s.charAt(j++)] = false;
}
ans = Math.max(ans, i - j + 1);
ss[c] = true;
}
return ans;
}
}
C++
class Solution {
public:
int lengthOfLongestSubstring(string s) {
bool ss[128] = {false};
int n = s.size();
int ans = 0;
for (int i = 0, j = 0; i < n; ++i) {
while (ss[s[i]]) {
ss[s[j++]] = false;
}
ss[s[i]] = true;
ans = max(ans, i - j + 1);
}
return ans;
}
};
Go
func lengthOfLongestSubstring(s string) (ans int) {
ss := make([]bool, 128)
j := 0
for i, c := range s {
for ss[c] {
ss[s[j]] = false
j++
}
ss[c] = true
ans = max(ans, i-j+1)
}
return
}
TypeScript
function lengthOfLongestSubstring(s: string): number {
let ans = 0;
const vis = new Set<string>();
for (let i = 0, j = 0; i < s.length; ++i) {
while (vis.has(s[i])) {
vis.delete(s[j++]);
}
vis.add(s[i]);
ans = Math.max(ans, i - j + 1);
}
return ans;
}
方法二
TypeScript
function lengthOfLongestSubstring(s: string): number {
let ans = 0;
const n = s.length;
const ss: boolean[] = new Array(128).fill(false);
for (let i = 0, j = 0; i < n; ++i) {
while (ss[s[i]]) {
ss[s[j++]] = false;
}
ss[s[i]] = true;
ans = Math.max(ans, i - j + 1);
}
return ans;
}
Swift
class Solution {
func lengthOfLongestSubstring(_ s: String) -> Int {
var ss = Array(repeating: false, count: 128)
var ans = 0
var j = s.startIndex
for i in s.indices {
let c = s[i]
while ss[Int(c.asciiValue!)] {
ss[Int(s[j].asciiValue!)] = false
j = s.index(after: j)
}
ans = max(ans, s.distance(from: j, to: i) + 1)
ss[Int(c.asciiValue!)] = true
}
return ans
}
}