四个个都是滑动窗口问题,后面是第三道题的大小顶堆的解法(第二题和第三题我做出来了)题解还是看这里:https://leetcode-cn.com/
from collections import deque
# 1438. 绝对差不超过限制的最长连续子数组
class Solution(object):
def longestSubarray1(self, nums, limit):
"""
:type nums: List[int]
:type limit: int
:rtype: int
"""
length = len(nums)
if length <= 1:
return length
q = list()
q.append(nums[0])
index = 1
count = float("-inf")
while q and index < length:
new_q = []
q_len = len(q)
flag = False
for i in range(q_len):
# 超界了,就将i之后的赋值给new_q
if i < q_len - 1 and abs(q[i] - nums[index]) > limit:
new_q = q[i+1:]
flag = True
if i == q_len - 1 and abs(q[i] - nums[index]) > limit:
new_q = []
flag = True
if flag:
new_q.append(nums[index])
q = new_q[:]
else:
q.append(nums[index])
count = max(count, len(q))
if len(q) >= 17:
print(q)
index += 1
return count
def longestSubarray2(self, nums, limit: int) -> int:
s = list()
n = len(nums)
left = right = ret = 0
while right < n:
s.append(nums[right])
s = sorted(s)
while s[-1] - s[0] > limit:
s.remove(nums[left])
left += 1
ret = max(ret, right - left + 1)
right += 1
return ret
def longestSubarray(self, nums, limit: int) -> int:
n = len(nums)
# queMax 是一个递减序列, queMin是一个递增序列;queMax的0位置元素必须是最大的,queMin的首部元素必须是最小的
queMax, queMin = deque(), deque()
left = right = ret = 0
while right < n:
while queMax and queMax[-1] < nums[right]:
queMax.pop()
while queMin and queMin[-1] > nums[right]:
queMin.pop()
# queMax和queMin同时将这个数字添加进去
queMax.append(nums[right])
queMin.append(nums[right])
# queMax[0] - queMin[0] 最大值和最小值的差如果大于limit,则说明当前加入的nums[left]
# 导致当前窗口不满足题意,由于ret已经记录了上一次的最大长度,所以窗口右移,看看是否有比当前窗口更长的值
# while 循环保证了,窗口中最大值和最小值满足题意(也就是整个窗口都满足了题意),left+1窗口左移
while queMax and queMin and queMax[0] - queMin[0] > limit:
if nums[left] == queMin[0]:
queMin.popleft()
if nums[left] == queMax[0]:
queMax.popleft()
left += 1
# 保存最大的长度
ret = max(ret, right - left + 1)
right += 1
return ret
if __name__ == '__main__':
nums = [4, 2, 2, 2, 4, 4, 2, 2]; limit = 0
nums = [10, 1, 2, 4, 7, 2]; limit = 5
s1 = Solution()
root = s1.longestSubarray(nums, limit)
print(root)
import bisect
# 1004. 最大连续1的个数 III
class Solution(object):
def longestOnes1(self, A, K):
"""
:type A: List[int]
:type K: int
:rtype: int
"""
left = right = ret = 0
count_0 = 0
length = len(A)
while right < length:
if A[right] == 0:
count_0 += 1
while count_0 > K:
if A[left] == 0:
count_0 -= 1
left += 1
ret = max(ret, right - left + 1)
right += 1
return ret
def longestOnes2(self, A, K):
"""
:type A: List[int]
:type K: int
:rtype: int
"""
left = right = ret = 0
count_0 = 0
length = len(A)
while right < length:
if A[right] == 0:
count_0 += 1
if count_0 > K:
if A[left] == 0:
count_0 -= 1
left += 1
ret = max(ret, right - left + 1)
right += 1
return ret
def longestOnes(self, A, K):
n = len(A)
P = [0]
for num in A:
# 二分法计算前缀数组
P.append(P[-1] + (1 - num))
ans = 0
for right in range(n):
left = bisect.bisect_left(P, P[right + 1] - K)
ans = max(ans, right - left + 1)
return ans
if __name__ == '__main__':
A = [1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0];
K = 2
A = [0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1];
K = 3
# A = [1, 1, 0, 0, 0];
# K = 0
s1 = Solution()
root = s1.longestOnes(A, K)
print(root)
# 480. 滑动窗口中位数
from sortedcontainers import SortedList
from bisect import bisect_left
class Solution(object):
def medianSlidingWindow1(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[float]
"""
left = 0
right = k
length = len(nums)
ret_list = []
mid_list = SortedList()
key = (k-1)//2
while right <= length:
mid_list.update(nums[left: right])
# 判断奇偶
if k & 1 == 1:
mid_value = mid_list[key]
else:
mid_value = (mid_list[key] + mid_list[key + 1]) / 2
right += 1
left += 1
ret_list.append(mid_value)
mid_list.clear()
return ret_list
def medianSlidingWindow2(self, nums, k: int):
n = len(nums)
window = []
ans = []
for i in range(n):
idx = bisect_left(window, nums[i])
window[idx:idx] = [nums[i]]
if len(window) > k:
q = nums[i - k]
idx = bisect_left(window, q)
window[idx: idx + 1] = []
if len(window) == k:
median = (window[k // 2] + window[(k - 1) // 2]) / 2
ans.append(median)
return ans
def medianSlidingWindow3(self, a, k: int):
ans = []
for i in range(0, len(a) - k + 1):
ls = a[i: i + k]
ls.sort()
if (k % 2): # 奇数
ans.append(ls[k // 2])
else: # 偶数
ans.append((ls[k // 2 - 1] + ls[k // 2]) / 2)
return ans
def medianSlidingWindow(self, nums, k: int):
# 使用python内置的二分法库
cur = sorted(nums[:k])
def get_mid():
return (cur[(k-1) // 2] + cur[k // 2]) / 2
ret = [get_mid()]
for i in range(k, len(nums)):
cur.insert(bisect_left(cur, nums[i]), nums[i])
cur.pop(bisect_left(cur, nums[i - k]))
ret.append(get_mid())
return ret
if __name__ == '__main__':
nums = [1, 3, -1, -3, 5, 3, 6, 7]; k = 3
s1 = Solution()
root = s1.medianSlidingWindow(nums, k)
print(root)
import heapq
import collections
class Heap:
def __init__(self, name="min"):
self.arr = []
self.f = lambda x: x if name == "min" else -x
def push(self, num):
heapq.heappush(self.arr, self.f(num)) # 推入一个
def pop(self):
return self.f(heapq.heappop(self.arr)) # 弹出堆顶
def top(self):
return self.f(self.arr[0])
def empty(self):
return len(self.arr) == 0
class Solution:
def medianSlidingWindow(self, nums, k: int):
small = Heap(name="max") # 较小数字部分使用大根堆
big = Heap(name="min") # 较大数字部分使用小根堆
get_mid = lambda x, y: x.top() if k % 2 else (x.top() + y.top()) / 2
mp = collections.defaultdict(int)
for i in range(k):
small.push(nums[i])
for i in range(k//2):
big.push(small.pop())
ans = [get_mid(small, big)]
for i in range(k, len(nums)):
balance = 0
l, r = nums[i-k], nums[i] # 将被删除的窗口最左元素和将被添加到窗口最右的元素
mp[l] += 1 # 左窗口元素记账
if l <= small.top():
balance -= 1 # 较小数字堆需删除一个元素
else:
balance += 1 # 较大数字堆需删除一个元素
if r <= small.top():
balance += 1 # 较小数字堆添加一个元素
small.push(r)
else:
balance -= 1 # 较大数字堆添加一个元素
big.push(r)
"""
此时balance取值可能是:
balance | small | big | 解释
0 | -1+1 | | 较小数字堆删除一个元素添加一个元素,两边还是平衡的
0 | | +1-1 | 较大数字堆删除一个元素添加一个元素,两边还是平衡的
-2 | -1 | -1 | 较小数字堆删除一个元素,较大数字堆添加一个元素,失衡
2 | +1 | +1 | 较大数字堆删除一个元素,较小数字堆添加一个元素,失衡
"""
# 较小数字堆挪一个给较大数字堆(3,3)->(4,2)->(3,3)或者(4,3)->(5,2)->(4,3)
if balance == 2:
big.push(small.pop())
# 较大数字堆挪一个给较小数字堆(3,3)->(2,4)->(3,3)或者(4,3)->(3,4)->(4,3)
if balance == -2:
small.push(big.pop())
# 重新达到平衡了,该看看堆顶是不是待删除元素了
while not small.empty() and mp[small.top()]:
mp[small.top()] -= 1
small.pop()
while not big.empty() and mp[big.top()]:
mp[big.top()] -= 1
big.pop()
# 为什么删除堆顶元素后不用重新平衡两边堆了呢?
ans.append(get_mid(small, big))
return ans
if __name__ == '__main__':
nums = [1, 3, -1, -3, 5, 3, 6, 7]; k = 3
s1 = Solution()
s1.medianSlidingWindow(nums, k)
# 1052. 爱生气的书店老板
class Solution(object):
def maxSatisfied1(self, customers, grumpy, X):
"""
:type customers: List[int]
:type grumpy: List[int]
:type X: int
:rtype: int
"""
length_g = len(grumpy)
left = 0
right = X
init_list = [0 for _ in range(X)]
ret_count = 0
while right < length_g + 1:
new_count = 0
new_grumpy = grumpy[:left] + init_list[:] + grumpy[right:]
for i in range(length_g):
if new_grumpy[i] != 1:
new_count += customers[i]
ret_count = max(ret_count, new_count)
left += 1
right += 1
print(ret_count)
return ret_count
def maxSatisfied2(self, customers, grumpy, X):
"""
:type customers: List[int]
:type grumpy: List[int]
:type X: int
:rtype: int
"""
length_g = len(grumpy)
left = 0
right = X
init_list = [0 for _ in range(X)]
ret_count = 0
for i in range(length_g):
if grumpy[i] != 1:
ret_count += customers[i]
ret_max = 0
while right < length_g + 1:
new_grumpy = grumpy[:left] + init_list[:] + grumpy[right:]
prev_grumpy = grumpy[:left - 1] + init_list[:] + grumpy[right - 1:] if left else grumpy
cur_sum = 0
pre_sum = 0
if left:
for j in range(left-1, right):
if new_grumpy[j] != 1:
cur_sum += customers[j]
if prev_grumpy[j] != 1:
pre_sum += customers[j]
else:
for j in range(left, right):
if new_grumpy[j] != 1:
cur_sum += customers[j]
if prev_grumpy[j] != 1:
pre_sum += customers[j]
ret_count += (cur_sum - pre_sum)
ret_max = max(ret_max, ret_count)
left += 1
right += 1
return ret_max
def maxSatisfied(self, customers, grumpy, X):
"""
:type customers: List[int]
:type grumpy: List[int]
:type X: int
:rtype: int
"""
length = len(grumpy)
if X >= length:
return sum(customers
)
init_sum = 0
for i in range(length):
if grumpy[i] == 0:
init_sum += customers[i]
temp_sum = 0
for i in range(X):
if grumpy[i] == 1:
temp_sum += customers[i]
ret_sum = temp_sum
for i in range(X, length):
if grumpy[i] == 1:
temp_sum += customers[i]
if grumpy[i-X] == 1:
temp_sum -= customers[i-X]
ret_sum = max(ret_sum, temp_sum)
return ret_sum + init_sum
if __name__ == '__main__':
s1 = Solution()
customers = [1, 0, 1, 2, 1, 1, 7, 5]; grumpy = [0, 1, 0, 1, 0, 1, 0, 1]; X = 3
# customers = [5, 8]; grumpy = [0, 1]; X = 1
root = s1.maxSatisfied(customers, grumpy, X)
print(root)