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)
posted @   楠海  阅读(48)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示