(Leetcode) 长度最小的子数组 - Python实现

题目:长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。

示例
输入: s = 7, nums = [2,3,1,2,4,3],输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。
进阶:
如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。

------------------------------------------------------------------

解法1:最容易想到的方法,直接遍历所有可能的组合。时间复杂度:O(n^2)

class Solution(object):
    def minSubArrayLen(self, s, nums):
        """
        :type s: int
        :type nums: List[int]
        :rtype: int
        """

        if not nums:
            return 0
        li = []
        for i in range(len(nums)-1):
            for j in range(i+1, len(nums)+1):
                # print(nums[i:j])
                if sum(nums[i:j]) >= s:
                    li.append(len(nums[i:j]))
        # print(li)
        if len(li) == 0:
            return 0
        else:
            return min(li)

解法2:使用python自带的 enumerate() 方法来遍历。时间复杂度:O(n^2)

enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。

语法:enumerate(sequence, [start=0])
参数:sequence -- 一个序列、迭代器或其他支持迭代对象。
           start -- 下标起始位置。

class Solution(object):
    def minSubArrayLen(self, s, nums):
        """
        :type s: int
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0

        minLen = len(nums)+1
        for i, _ in enumerate(nums):
            total= 0
            for j, tmp in enumerate(nums[i:]):
                total += tmp
                if total >= s:
                    minLen = min(minLen, j+1)
        
        # 如果没有发生任何替换, 说明不存在
        if minLen == len(nums)+1:
            return 0

        return minLen

解法3:  双指针,或对撞指针。不断判断跟s的大小,如果大了,说明元素太多,左移;反之小了,右移。时间复杂度:O(n)

class Solution(object):
    def minSubArrayLen(self, s, nums):
        """
        :type s: int
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0

        # 创建2个指针
        pointer1, pointer2 = 0, 0

        total = 0
        nums_len = len(nums)
        minL = nums_len + 1
        while pointer1 < nums_len:
            if pointer2 < nums_len and total < s:
                total += nums[pointer2]
                pointer2 += 1
            else:
                total -= nums[pointer1]
                pointer1 += 1

            if total >= s:
                minL = min(minL, pointer2-pointer1)

        if minL == nums_len + 1:
            return 0

        return minL

解法4:因为涉及到 "连续子数组",一旦提到连续二字,我们想到可以通过 二分法 来简化处理。时间复杂度:O(nlog(n))。

class Solution(object):
    def sumJudge(self, nums, index, s):
        sum = 0
        for i, _ in enumerate(nums):
            if i >= index:
                sum -= nums[i-index]
            sum += nums[i]

            if sum >= s:
                return True
        return False


    def minSubArrayLen(self, s, nums):
        """
        :type s: int
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0

        left = 1
        right = len(nums)
        result = 0
        while left <= right:
            mid = left + (right - left)//2
            if self.sumJudge(nums, mid, s):
                right = mid - 1
                result = mid
            else:
                left = mid + 1
        return result

解法5:动态规划法,不需要每次循环都计算加和。时间复杂度:O(nlog(n))。

class Solution(object):
    def minSubArrayLen(self, s, nums):
        """
        :type s: int
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        res = len(nums) + 1
        low, high = 0, -1
        subsum = 0
        while (low < len(nums)):
            # 
            if (subsum < s) and (high+1 < len(nums)):
                high += 1
                subsum += nums[high]
            else:
                subsum -= nums[low]
                low += 1

            if subsum >= s:
                res = min(res, high - low + 1)
        return res if res != len(nums) + 1 else 0

参考

https://www.runoob.com/python/python-func-enumerate.html

https://blog.csdn.net/qq_17550379/article/details/80540430

https://blog.csdn.net/qq_32424059/article/details/88091040

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值