LC 209, 904, 76, 59 Sliding-Window Problems
Second part of Array, (List in python, I guess). LC977 is covered in the last post already.
LC 209. Minimum Size Subarray Sum
From the first site, the brute force method should be clear. Where from here, #
209.长度最小的子数组, the sliding window method is introduced, which helps to reduce the Time complexity to just
O
(
n
)
O(n)
O(n).
# LC 209
# Credit to Carl
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
ret = len(nums) + 1
for i in range(len(nums)):
acc = 0
for j in range(i, len(nums)):
acc += nums[j]
if acc >= target:
ret = min(ret, j - i + 1)
break
return 0 if ret > len(nums) else ret
Logic
If we divide two cases, we can bring the inner while
loop out, where:
-
Condition Unfulfilled (feeding the condition):
- When:
sum(nums[i,j+1]) < 0
, at this time, the current sum is not enough yet. - Action: If the sum is not enough, we could just add more numbers, then the left bound move to the right.
- When:
-
Condition Fulfilled:
- When:
sum(nums[i,j+1]) >= 0
. - Action: the left bound could move to the right, to reach the array with the least length.
- In the above code, As long as the condition is reached, the shortest array is calculated without disruptions. It will sort of converges quicker than the below code (on first site, but actually speed is the same).
- When:
def min_sub_array_len(self, target: int, nums: List[int]) -> int:
low = 0
high = -1
acc = 0
count = len(nums) + 1
while low < len(nums):
# feeding the condition
if acc < target:
high += 1
# higher bound reached the limit
# but the condition is not yet met
if high >= len(nums):
break
acc += nums[high]
else:
# condition fulfilled
count = min(count, high - low + 1)
acc -= nums[low]
low += 1
return count if len(nums) >= count else 0
LC 904. Fruit Into Baskets
Well, look a bit of disgusting, who actually plants fruits like that? Straight to hell. Anyway, this question looks also like a sliding-window question, but the condition to check upon on is not so easy.
Logic
- Firstly, I run-length encoded the input, so that input of [ 1 , 1 , 1 , 2 , 2 , 3 , 2 , 2 ] [1,1,1,2,2,3,2,2] [1,1,1,2,2,3,2,2] becomes [ 1 : 3 , 2 : 2 , 3 : 1 , 2 : 2 ] [1:3, 2:2, 3:1, 2:2] [1:3,2:2,3:1,2:2], where ( k e y , v a l u e ) (key, value) (key,value) pairs corresponds to the ( t y p e , f r e q u e n c e ) (type, frequence) (type,frequence).
Gradly, we have a window of fix size two, where window.size == len(basket)
.
-
Condition Unfulfilled (throw away to fit):
- When:
len(basket) > 2
, at this time, we are not feeding more to fulfill the condition, we need to take things out. However, we can’t just throw out everything that is in the window, the last occurance is still usable, and should be tested in the next window. For example, after testing the window of [ 1 : 3 , 2 : 2 ] [1:3, 2:2] [1:3,2:2], we should then choose the window of [ 2 : 2 , 3 : 1 ] [2:2, 3:1] [2:2,3:1]. - Action: Take the left bound to be the last occurance.
- When:
-
Condition Fulfilled:
- When:
len(basket) <= 2
. - Action: Take in more trees to see if they fit.
- When:
LC 76. Minimum Window Substring
Logic:
-
Analogue to a slide window problem.
-
Condition Unfulfilled (feeding the condition):
- When:
counter of s[i,j+1] < counter of [t]
, where counter only counts for the characters that are in t. - Action: Move the left bound
j
left.
- When:
-
Condition Fulfilled:
- When:
counter of s[i,j+1] < counter of [t]
. - Action: Move the right bound
i
left.
- When:
-
Notice: if
t = "ABC"
, we are not necessarily one step closer if we seee any ofA
,B
orC
ins
, we only need 1 occurance of each, and no more. -
However, if there is more in the substring when we move right bound
i
, we should also remember that, and the condition is only break when not enough chars are included.
def minWindow(self, s: str, t: str) -> str:
if len(s) < len(t) or t == "":
return ""
s_lst = list(s)
t_lst = list(t)
t_ct = Counter(t_lst)
acc_ct = t_ct.copy()
length = len(s_lst)
# total char to match
total_count = len(t_lst)
# current best choise
min_len = len(s_lst) + 1
start, end = -1, 0
for i in acc_ct:
acc_ct[i] = 0
# left
i = 0
# right
j = 0
while j < length:
c = s[j]
if c in acc_ct:
# cur state change
if acc_ct[c] < t_ct[c]:
total_count -= 1
acc_ct[c] += 1
if total_count <= 0:
while total_count == 0:
if j - i + 1 < min_len:
end = j
start = i
min_len = j - i + 1
c2 = s[i]
if c2 in acc_ct:
acc_ct[c2] -= 1
# there is already not enough char in [start:end+1]
if acc_ct[c2] < t_ct[c2]:
total_count += 1
i += 1
j += 1
# start, end not found
if start == -1:
return ""
return s[start : end + 1]
LC 59
Logic:
- Simulation, not much to add, easy for me. Just remember the boundary conditions.
Summary:
-
Figure out when the condition is fulfilled, and when is not, then sliding-window problems are not so difficult, and they will even be elegant.
-
Total time: About a whole afternoon.