Python算法题集_和为K的子数组

本文为Python算法题集之一的代码示例

题目560:和为K的子数组

说明:给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数

子数组是数组中元素的连续非空序列。

示例 1:

输入:nums = [1,1,1], k = 2
输出:2

示例 2:

输入:nums = [1,2,3], k = 3
输出:2

提示:

  • 1 <= nums.length <= 2 * 104
  • -1000 <= nums[i] <= 1000
  • -107 <= k <= 107

- 问题分析

  1. 本题为求子数组和为K,子数组为非空的连续元素

  2. 主要的计算为两个,1是元素求和,而是比较和与K

  3. 基本的遍历为双层循环,从第一个元素开始,计算从此元素开始有多少次和为K,所以基本的时间算法复杂度为(On2)

- 优化思路

  1. 优化的思路,一是减少计算次数,二是减少检索次数和提升检索效率

  2. 标准的优化思路,前缀和【从第1个元素累加到第n个元素的和,称为第n个前缀和】,只要出现2个前缀和的差=k,则这两个下标之间的数组即满足要求

  3. 进一步优化,第n个元素前缀和为isum_n,则1至n-1如果有x个前缀和为k-isum_n,则第n个元素可以在1至n-1之间形成x个和为k的子数组

  4. 以上优化都是考虑前缀和差,因此对于nums只有一个元素的情况要单独进行处理


  1. 标准版【双循环】,毫无疑问,直接超时

    注意:

    • CheckFuncPerf是我写的函数用时和内存占用模块,地址在这里:测量函数运行用时、内存占用的代码单元CheckFuncPerf.py以及使用方法
    • 测试的超长nums文件是官网的,已经上传到CSDN,地址在这里:和为K的子数组测试用超长数组
    import CheckFuncPerf as cfp
    
    def subarraySum_base(nums, k):
        result=0
        for iIdx in range(len(nums)):
            iSum = nums[iIdx]
            if iSum == k:
                result += 1
            for jIdx in range(iIdx+1, len(nums)):
                iSum += nums[jIdx]
                if iSum == k:
                    result += 1
        return result
    
    testcase_big1 = open(r'testcase/hot10_big1.txt', mode='r', encoding='utf-8').read().replace('[', '').replace(']', '')
    testcase_big1 = testcase_big1.split(',')
    nums = [int(x) for x in testcase_big1]
    k = 714
    
    result = cfp.getTimeMemoryStr(subarraySum_base, nums, k)
    print(result['msg'], '执行结果 = {}'.format(result['result']))
    # 运行结果
    函数 subarraySum_base 的运行时间为 10591.62 ms;内存使用量为 4.00 KB 执行结果 = 40
    
  2. 优化版【提前计算前缀和,直接计算前缀和之差】,有想法,然并卵,超时依旧

    import CheckFuncPerf as cfp
    
    def subarraySum_ext1(nums, k):
        if len(nums)==1:
            if nums[0] == k:
                return 1
            else:
                return 0
        isumpref=[0] * len(nums)
        iSum = 0
        for iIdx in range(len(nums)):
            iSum += nums[iIdx]
            isumpref[iIdx] = iSum
        result=0
        for iIdx in range(len(nums)):
            if iIdx==0 and nums[iIdx] == k:
                result += 1
            if isumpref[iIdx] == k:
                result += 1
            for jIdx in range(iIdx+1, len(nums)):
                if isumpref[jIdx]-isumpref[iIdx] == k:
                    result += 1
        return result
    
    testcase_big1 = open(r'testcase/hot10_big1.txt', mode='r', encoding='utf-8').read().replace('[', '').replace(']', '')
    testcase_big1 = testcase_big1.split(',')
    nums = [int(x) for x in testcase_big1]
    k = 714
    
    result = cfp.getTimeMemoryStr(subarraySum_ext1, nums, k)
    print(result['msg'], '执行结果 = {}'.format(result['result']))
    # 运行结果
    函数 subarraySum_ext1 的运行时间为 10508.87 ms;内存使用量为 732.00 KB 执行结果 = 40
    
  3. 优化改进版【单层循环,将到第n个元素的所有前缀和的计数存入字典】,优化所见略同,仅超越68%Python算法题集_和为K的子数组_第1张图片

    import CheckFuncPerf as cfp
    
    def subarraySum_ext2(nums, k):
        dictsumpref = {}
        isum, iresult = 0, 0
        for num in nums:
            isum += num
            if isum == k:
                iresult += 1
            if isum - k in dictsumpref:
                iresult += dictsumpref[isum - k]
            dictsumpref[isum] = dictsumpref.get(isum, 0) + 1
        return iresult
    
    testcase_big1 = open(r'testcase/hot10_big1.txt', mode='r', encoding='utf-8').read().replace('[', '').replace(']', '')
    testcase_big1 = testcase_big1.split(',')
    nums = [int(x) for x in testcase_big1]
    k = 714
    
    result = cfp.getTimeMemoryStr(subarraySum_ext2, nums, k)
    print(result['msg'], '执行结果 = {}'.format(result['result']))
    # 运行结果
    函数 subarraySum_ext2 的运行时间为 3.99 ms;内存使用量为 160.00 KB 执行结果 = 40
    

    一日练,一日功,一日不练十日空

    may the odds be ever in your favor ~

你可能感兴趣的:(Python,算法,python,开发语言,leetcode)