python leetcode 209. 长度最小的子数组 [中等题]

一 读懂题目

二. 分析,推导解法,产生思路。

1 n 滑动窗口: 先右指针找到满足条件的连续子数组后,再移动左指针,直到未出现满足条件的连续子数组,再移动右指针;注意左指针移动时用while并判断是否存在更小的连续子组;

2 nlogn 前缀和+二分查找:

注意前缀和的第一个为0;二分查找条件与边界设置l<r & if大则r=mid & if小l=mid+1;

3 n*n 暴力搜索:双循环;注意if判断的位置,才能判断出不同的子组和;

三 代码实现

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

        # 1 滑动窗口 n
        right = 0
        left = 0
        temp_sum = 0
        nums_len = len(nums) 
        min_len = nums_len+1
        while right < nums_len:
            temp_sum += nums[right]
            # print(left, right, temp_sum, min_len)
            # 当右指针找到满足条件的连续子数组后,移动左指针,直到未出现满足条件的连续子数组,再移动右指针
            while temp_sum >= target :  # 重点为while
                # 判断是否为长度最小的连续子数组
                min_len = min(min_len, right-left+1)
                temp_sum -= nums[left]
                left += 1
            right += 1
 
        return 0 if min_len == nums_len+1 else min_len


        # 复杂化了:检验滑动窗口中是否存在更小子组是正确的,但代码太复杂;
        # 思路错误:没有必要维持较大的窗口,再找滑动窗口中是否存在更小子组,因为找的是最小子组

        # def checksub(l,r, min_len, cur_len,cur_sum):
        #     # 当新增一个数字后,子组大于target时,用于检验滑动窗口内是否存在更小的子组大于target
        #     while l <= r:
        #         if cur_sum >= target:   # 存在更小的子组
        #             if cur_len < min_len:
        #                 min_len = cur_len
        #         cur_sum = cur_sum-nums[l]
        #         cur_len = cur_len-1
        #         l = l+1
        #     return min_len

        # l,r = 0,0   # 初始化子组开始,结束指针
        # cur_sum = nums[r]
        # min_len, cur_len = float("inf"), 1   # 子组长度
        # while True:
        #     if cur_sum >= target: # 当前子数组和与target长度判断
        #         # 若子数组和大于target,则比较最小子组长度
        #         if cur_len < min_len:
        #             # 若当前子组长度小于最小子组长度,则记录最新最小子组长度,并减去开始指针对应整数且更新开始指针
        #             min_len = cur_len
        #             cur_sum = cur_sum-nums[l]
        #             cur_len = cur_len -1
        #             l = l+1  
        #         # 判断子组是否存在更小的子组
        #         # print(min_len)
        #         min_len = checksub(l,r,min_len,cur_len,cur_sum)   # 考察哪些参数可以不传过去
        #         # print(min_len,submin_len)
        #     if r == len(nums)-1:
        #         break
        #     # r后移及操作
        #     r = r+1
        #     cur_sum = cur_sum + nums[r]
        #     cur_len = cur_len + 1

        # if min_len == float("inf"):
        #     return 0
        # return min_len

        # 测试用例:18/21 
        # 报错用例:上千的数据量的用例无法通过;  报错原因:超出时间限制;由于每次都要遍历多次子组


        # l,r = 0,-1   # 初始化子组开始,结束指针
        # cur_sum = 0
        # min_len, cur_len = float("inf"), 0   # 子组长度
        # end_flag = True
        # while l < len(nums):    #  遍历数组
        #     print(l,r,min_len, cur_len,cur_sum)
        #     if r == len(nums)-1: end_flag = False# r移到最右边了
        #     if r < len(nums)-1 and end_flag:    
        #         r = r+1 #若r未移动到末尾则cur_sum加上结束整数且cur_len加1,r移动
        #         cur_sum = cur_sum + nums[r]
        #         cur_len = cur_len + 1
        #     else:   #若r移动到末尾则cur_sum减去开始整数且cur_len减1,l移动
        #         cur_sum = cur_sum-nums[l]
        #         cur_len = cur_len-1
        #         l = l+1 

        #     if cur_sum >= target: # 当前子数组和与target长度判断
        #         # 若子数组和大于target,则比较最小子组长度
        #         if cur_len < min_len:
        #             # 若当前子组长度小于最小子组长度,则记录最新最小子组长度,并减去开始指针对应整数且更新开始指针
        #             min_len = cur_len
        #             if end_flag:    # 若r移到最右边了,则不能重复移动l
        #                 cur_sum = cur_sum-nums[l]
        #                 cur_len = cur_len -1
        #                 l = l+1                        

        # if min_len == float("inf"):
        #     return 0
        # return min_len

        # 之前的思路;滑动窗口来遍历子组;
        # 1) 均从下标0开始,固定l,移动r,直到找到第一个符合条件的子组;再移动一位l且移动一位r即改变窗口;
        # 2)重复上面的过程,直到r到len-1,再仅移动l;
        # 测试用例:16/21
        # 报错用例:[5,1,3,5,10,7,4,9,2,8]  报错原因:因为10比较大;未考虑到新增加一个数字后,前面的整个子组可能有符合条件的更小子组;





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

        # 2 前缀和 + 二分查找 nlogn
        min_len = len(nums)+1
        sums = [0]
        sum_t = 0
        for i in range(len(nums)):  # 计算并保留前缀和(第一项为0)
            sum_t += nums[i]
            sums.append(sum_t)
            
        # 二分查找得到大于或等于 i 的最小下标mid
        for i in range(len(nums)+1):
            l,r = 0, len(nums)+1
            while(l<r):
                mid = (l+r)/2
                if sums[mid]-sums[i] >= target: # 找到满足条件的子组
                    if min_len > mid-i:
                        min_len = mid-i
                    r = mid
                else:
                    l = mid +1

        return 0 if min_len == len(nums)+1 else min_len




class Solution(object):
    def minSubArrayLen(self, target, nums):
        """
        :type target: int
        :type nums: List[int]
        :rtype: int
        """
        # n*n 的做法:暴力枚举法
        if not nums:
            return 0

        n = len(nums)
        min_len = n+1
        for i in range(n):
            cur_sum = 0
            for j in range(i,n): # 计算字串[i,n]之和
                cur_sum += nums[j]
                if cur_sum >= target: # 重点为在每次加法后判断,这样才能验证每个字串
                    if min_len > j-i+1 :
                        min_len = j-i+1

        return 0 if min_len == n+1 else min_len
        # 测试用例:18/21 
        # 报错用例:上千的数据量的用例无法通过;  报错原因:python超出时间限制;由于每次都要遍历多次子组




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值