zoukankan      html  css  js  c++  java
  • 171-滑动窗口问题

    四个个都是滑动窗口问题,后面是第三道题的大小顶堆的解法(第二题和第三题我做出来了)题解还是看这里: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)
    
  • 相关阅读:
    Python环境搭建详解(Window平台)
    扎心了Python
    解决Git
    Android入门教程(四)
    HEXO快速搭建自己的博客
    每日Android一问等你来解答-什么是Activity的生命周期?
    如何才能够系统地学习Java并发技术?
    LeetCode刷题指南(字符串)
    学生时代的最后一个新年,请一定要做这五件事
    20位程序员关于求职的疑问,以及我给出的参考答案
  • 原文地址:https://www.cnblogs.com/liuzhanghao/p/14431144.html
Copyright © 2011-2022 走看看