904. 水果成籃
- 思路
- example
- 兩個籃子恨统,返回你可以收集的水果的 最大 數(shù)目
- 等價于“最長的含兩個不同數(shù)字的連續(xù)子序列長度”
- Two Pointer, Sliding Window, -->-->
- left, right = 0, 0
- use hash, i.e., dict to record the fruits
- dict[num] = freq
- len(dict) is always <= 2
- [left, right] is feasible if len(dict) <= 2,左閉右閉,可行窗口
- 注意最大與最小的處理邏輯不同衅码。
本題
遍歷 right:
處理right
循環(huán)收縮left找到可行窗口
處理可行窗口
- 復雜度. 時間:O(n), 空間: O(1)
class Solution:
def totalFruit(self, fruits: List[int]) -> int:
n = len(fruits)
left, right = 0, 0
basket = collections.defaultdict(int)
res = 0
while right < n:
# "add"/test current fruit into the basket
basket[fruits[right]] += 1
# then check the feasibility
while len(basket) > 2: # more than 2 types of fruits, [left, right] is not feasible
# move left
basket[fruits[left]] -= 1
if basket[fruits[left]] == 0:
del basket[fruits[left]] # need to del this otherwise we could not use len(basket)
left += 1
# [left, right] is feasible, update res
res = max(res, right - left + 1)
# move right
right += 1
return res
- try this
import collections
dict1 = collections.defaultdict(int)
print(dict1)
print(dict1[2])
print(len(dict1))
print(dict1[3])
print(len(dict1))
print(dict1)
76. 最小覆蓋子串
- 思路
- example
- 等價于“最短的連續(xù)子串(包含t)"
- sliding window, -->-->
- left, right = 0, 0
- two hashes, cnt_s, cnt_t, "cnt[ch] = freq"
- feasible window [left, right]
- valid == len(t) (valid always <= len(t))
- it's possible that cnt_s[ch] > cnt_t[ch] for some ch in s[left: right+1]
- once find a feasible window, keep moving left to update the result (needs smallest substring)
-
Key: for a feasible window, cnt_s[s[right]] is exactly equal to cnt_t[s[right]]
hash: cnt_s (變化)漂羊,cnt_t (不變)
valid記錄當前窗口含有t元素的個數(shù)蒙挑。(valid 最大值n)
遍歷right:
處理right (更新cnt_s, valid)
如果窗口可行(size=n), 循環(huán)收縮left找到滿足要求的最小窗口 (更新cnt_s, valid, 答案)
- 復雜度. 時間:O(n), 空間: O(1)
class Solution:
def minWindow(self, s: str, t: str) -> str:
m, n = len(s), len(t)
if m < n:
return ''
# fix cnt_t
cnt_t = collections.defaultdict(int)
for ch in t:
cnt_t[ch] += 1
#
cnt_s = collections.defaultdict(int)
left, right = 0, 0
valid = 0
start, end = 0, -1
min_len = float('inf') # smallest length of feasible window
while right < m:
ch = s[right]
cnt_s[ch] += 1
if cnt_s[ch] <= cnt_t[ch]: # add one valid char
valid += 1
while valid == n: # [left, right] is a feasible, keep moving left to find the smallest window
cur_len = right - left + 1
if cur_len < min_len:
min_len = cur_len
start, end = left, right # record
cnt_s[s[left]] -= 1
if cnt_s[s[left]] < cnt_t[s[left]]: # cnt_t[s[left]] is at least 0 (defaultdict)
valid -= 1
left += 1
# move right
right += 1
return s[start:end+1]
- version 2: 每一步都把left指針移動到“最佳“位置幼东。
-
Key: for a feasible window, cnt_s[s[left]] is exactly equal to cnt_t[s[left]]
-
hash: cnt_s (變化)确镊,cnt_t (不變)
valid記錄當前窗口含有t元素的個數(shù)士骤。(valid 最大值n)
遍歷right:
處理right (更新cnt_s, valid)
循環(huán)收縮left直到左邊界處在最佳位置 (cnt_s[s[left]] == cnt_t[s[left]]),結束后得到“預可行”窗口(valid < n)
如果窗口可行蕾域,更新最小值
class Solution:
def minWindow(self, s: str, t: str) -> str:
m, n = len(s), len(t)
if m < n:
return ''
# fix cnt_t
cnt_t = collections.defaultdict(int)
for ch in t:
cnt_t[ch] += 1
#
cnt_s = collections.defaultdict(int)
left, right = 0, 0
valid = 0
start, end = 0, -1
min_len = float('inf') # smallest length of feasible window
while right < m:
ch = s[right]
cnt_s[ch] += 1
if cnt_s[ch] <= cnt_t[ch]: # add one valid char
valid += 1
# keep moving left to remove the unnecessary char, until cnt_s[s[left]] == cnt_t[s[left]]
while left <= right and cnt_s[s[left]] > cnt_t[s[left]]:
cnt_s[s[left]] -= 1
left += 1
# check feasibility
if valid == n: # now [left, right] will be the shortest feasible substring
cur_len = right - left + 1
if cur_len < min_len:
min_len = cur_len
start, end = left, right
# move right
right += 1
return s[start:end+1]
54. 螺旋矩陣
- 思路
- example
- size of matrix:
- slightly change the update style inside the loop
- 貪心策略:右拷肌,下,左旨巷,上巨缘。每個方向都盡可能搜索,這樣可以方便處理單行單列的情況采呐。
- deal with the boundary case (eg., one row, one column)
- should work for m==n case
- 復雜度. 時間:
, 空間: O(1)
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
m, n = len(matrix), len(matrix[0])
top, bottom = 0, m-1
left, right = 0, n-1
res = []
while top <= bottom and left <= right:
#-->
for j in range(left, right+1):
res.append(matrix[top][j])
# downward (right column)
for i in range(top+1, bottom+1):
res.append(matrix[i][right])
#<--
if top < bottom and left < right: # extra row or column updates
for j in range(right-1, left-1, -1):
res.append(matrix[bottom][j])
for i in range(bottom-1, top, -1):
res.append(matrix[i][left])
# update indices
top += 1
bottom -= 1
left += 1
right -= 1
return res
48. 旋轉圖像
- 思路
- example
- size of matrix:
先按主對角線翻轉
再每一行進行翻轉
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
def reverse(nums):
n = len(nums)
left, right = 0, n-1
while left < right:
nums[left], nums[right] = nums[right], nums[left]
left += 1
right -= 1
# step 1
n = len(matrix)
for i in range(n):
for j in range(i+1, n):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
# step 2
for i in range(n):
reverse(matrix[i])
數(shù)組總結
- 二分搜索
- 左閉右閉
- 左閉右開
- 雙指針
- 快慢若锁,前后, 斧吐。又固。。
- 滑動窗口
- 同向移動 -->-->
- left, right 初始化
- 外層循環(huán):right
- 內層:left
- 判斷當前窗口可行性煤率,移動left
- 計數(shù)
- hash技術
-
滑動窗口:本質是滿足了單調性,即左右指針只會往一個方向走且不會回頭仰冠。收縮的本質即去掉不再需要的元素。也就是做題我們可以先固定移動右指針蝶糯,判斷條件是否可以收縮左指針算范圍洋只。大家可以好好理解一下。From 芒果冰
- <--*-->
- -->*<--