LeetCode—4.滑动窗口

引言

  滑动窗口也是一种双指针(索引)的方式,顾名思义。使用双索引来表示一个滑动的窗口。

一、LeetCode—209

209.Minimum Size Subarray Sum
  给定一个整型数组和一个数字s,找到数组中最短的一个连续子数组,使得连续子数组的数字和sum>=s,返回这个最短的连续子数组的长度值

给定数组[2,3,1,2,4,3],s=7
输出[4,3],返回2

  • 连续子数组
  • 如果没有解怎么办?返回0
  • 有多个解的话该怎么办?返回一个还是多个?

解法一:暴力法
遍历所有连续子数组,计算其和sum(O(n)),验证sum>=s。
时间复杂度O(n^3)

如果将计算所有连续数组的sum转变为cumsum(提前计算好),则优化后的暴力解法的时间复杂度为O(n^2)

很明显,遍历计算所有连续子数组的过程中存在着大量的重复计算。

解法二:滑动窗口
两个指针left和right,left代表滑窗的左边框,right代表滑窗的右边框。两者分别向右滑动,前者能使窗口之间的和减小,后者能使窗口之间的和增大。开始时两者重合,窗口的和就是重合点所在的数。

  1. right向右移动,使和变大。当恰好大于等于s时,记录滑窗所包括的子数组的长度ans,若ans已有数值,需判断新值是否小于旧值,若是,则更新ans
  2. left向右滑动,判断是否仍大于等于s
  3. 若是,重复步骤2.若否,更新ans并转步骤1。直到右边框到达最右边。

通俗点来说,即没有大于s时,right往右移动,大于s时,left向右移动

class Solution:
    def findminarray(self, nums, s):
        return self.minSubArrayLen(nums, s)

    def minSubArrayLen(self, nums, s):
        #
        left, right, ans = 0, 0, len(nums) + 1
        # 创建一个累加和数组,将求和的时间复杂度从O(n)变为O(1)
        cumsum = []
        for num in nums:
            if not cumsum:
                cumsum.append(num)
            else:
                cumsum.append(cumsum[-1] + num)

        array_dict = {
    
    }
        while left < len(nums) and right < len(nums):
            if cumsum[right] - cumsum[left] + nums[left] < s:
                right += 1
            else:
                if right + 1 - left < ans:
                    ans = right + 1 - left  # 更新数组长度
                    array_dict[ans] = nums[left:right + 1]
                left += 1
        # 跳出循环的条件是right = len(nums)

        if ans != len(nums) + 1:
            return ans, array_dict[ans]
        else:
            return 0


def main():
    nums = [2, 3, 1, 2, 4, 3]
    s = 7
    ss = Solution()
    solution = ss.findminarray(nums, s)
    print('返回连续子数组及最小长度:', solution)


if __name__ == '__main__':
    main()

猜你喜欢

转载自blog.csdn.net/weixin_46649052/article/details/114624927