链表子串数组题, 用双指针别犹豫. 双指针家三兄弟, 各个都是万人迷.
快慢指针最神奇, 链表操作无压力. 归并排序找中点, 链表成环搞判定.
左右指针最常见, 左右两端相向行. 反转数组要靠它, 二分搜索是弟弟.
滑动窗口最困难, 子串问题全靠它. 左右指针滑窗口, 一前一后齐头进.
大致逻辑
T(2n)
、O(n)
left, right = 0, 0
while right < len(s):
# 增大窗口
window.add(s[right])
right += 1
while window needs shrink:
# 缩小窗口
window.remove(s[left])
left += 1
框架
- 寻找一个可行解
- 优化这个可行解
- 找到最优解
def slidingWindow(s: str, t: str):
need, window = defaultdict(int), defaultdict(int)
for c in t:
need[c] += 1
left, right, valid = 0, 0, 0
while right < len(s):
c = s[right] # c 是即将移入窗口的字符
right += 1 # 右移窗口
# ... 进行窗口内数据的一系列更新
print("window: [%d, %d)\n" % left, right)
# 判断左侧窗口是否要收缩
while window needs shrink:
d = s[left] # d 是即将移出窗口的字符
left += 1 # 左移窗口
# ... 进行窗口内数据的一系列更新
default dict
defaultdict(factory: function)
def def_value():
return "Not Present"
# Defining the dict
d = defaultdict(def_value)
76 最小覆盖子串
def minWindow(self, s: str, t: str) -> str:
need = defaultdict(int)
window = defaultdict(int)
for c in t:
need[c] += 1
left, right, valid = 0, 0, 0
start, lenght = 0, sys.maxsize
while right < len(s):
c = s[right] # c 是即将移入窗口的字符
right += 1 # 右移窗口
# ... 进行窗口内数据的一系列更新
if c in need:
window[c] += 1
if window[c] == need[c]:
valid += 1
# 判断左侧窗口是否要收缩
while valid == len(need):
if right - left < lenght:
start = left
lenght = right - left
d = s[left] # d 是即将移出窗口的字符
left += 1 # 左移窗口
# ... 进行窗口内数据的一系列更新
if d in need:
if window[d] == need[d]:
valid -= 1
window[d] -= 1
return "" if lenght == sys.maxsize else s[start:start+lenght]
567 s2的子串是否包含s1的排列
class Solution:
def checkInclusion(self, s1: str, s2: str) -> bool:
NEED, window = defaultdict(int), defaultdict(int)
for item in s1:
NEED[item] += 1
left, right = 0, 0
valid = 0
while right < len(s2):
c = s2[right]
right += 1
if c in NEED:
window[c] += 1
if window[c] == NEED[c]:
valid += 1
while right - left >= len(s1): # >
if valid == len(NEED): # len(s1)
return True
d = s2[left]
left += 1
if d in NEED:
if window[d] == NEED[d]:
valid -= 1
window[d] -= 1
return False
438 异位子串起始索引
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
NEED, window = defaultdict(int), defaultdict(int)
for item in p:
NEED[item] += 1
left, right = 0, 0
valid = 0
res = list()
while right < len(s):
c = s[right]
right += 1
if c in NEED:
window[c] += 1
if window[c] == NEED[c]:
valid += 1
while right - left >= len(p):
if valid == len(NEED):
res.append(left)
d = s[left]
left += 1
if d in NEED:
if window[d] == NEED[d]:
valid -= 1
window[d] -= 1
return res
3 最长无重复子串
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
window = defaultdict(int)
left, right = 0, 0
res = 0
while right < len(s):
c = s[right]
right += 1
window[c] += 1
while window[c] > 1:
d = s[left]
left += 1
window[d] -= 1
res = max(res, right - left)
return res