3. 无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
Solution
使用两个指针,不是每次移动一位,而是直接跳到对应的位置。通过移动这两个指针形成新的窗口。
滑动窗口中使用字典来保存字符及其索引,当出现重复字符时,移动指向窗口的左侧的指针以去除重复字符。
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
left = 0
max_len = 0
dic = {
}
for right, char in enumerate(s):
if s[right] in dic and dic[s[right]] >= left:
left = dic[s[right]] + 1
dic[s[right]] = right
max_len = max(right - left + 1, max_len)
right += 1
return max_len
438. 找到字符串中所有字母异位词
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例:
输入: s = “cbaebabacd”, p = “abc”
输出: [0,6]
Solution
仅当窗口的大小等于字符串 p 的长度时,窗口内的子串才有可能是字符串 p 的异位词。换句话说,窗口的大小是固定的。
我们可以使用哈希表来记录窗口内的每个字符的数量,以便快速判断窗口内的字符串是否是 p 的异位词。
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
p_counter = Counter(p)
res = []
for i in range(len(p) - 1, len(s)):
s_counter = Counter(s[i - len(p) + 1: i + 1])
if s_counter == p_counter:
res.append(i - len(p) + 1)
return res
需要注意的是,Python的切片操作不包括终止索引。
然而,这个算法的时间复杂度是O(n * m),其中n是字符串s的长度,m是字符串p的长度,因为对于s的每一个子串,我们都要计算它的字符计数。
如果只是在每次迭代时更新新的字符的计数,而不是重新计算整个窗口的字符的计数,也就是滑动窗口向右移动一步,新字符进入窗口,老字符离开窗口,只对新旧字符的计数进行增减,时间复杂度就可以从之前的 O(n*m) 降低到 O(n),其中 n 是字符串 s 的长度。这是因为对于 s 中的每一个字符,我们只执行常数时间的操作。
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
p_counter = Counter(p)
s_counter = Counter()
res = []
for i in range(len(s)):
s_counter[s[i]] += 1
if i >= len(p):
s_counter[s[i - len(p)]] -= 1
if s_counter == p_counter:
res.append(i - len(p) + 1)
return res