leetcode-连续子数组和为目标数值的整数倍 思路与代码

文章目录

    • 问题描述
    • 问题分析
    • 问题解法

问题描述

问题链接:https://leetcode.com/problems/continuous-subarray-sum/
给定一个非负数组和一个正数目标值k,请判断数组中是否存在一个连续的子数组,其加和为k的整数倍,即其加和等于n*k,其中n也为一个整数。

leetcode,medium,python
523:Continuous Subarray Sum

问题分析

拿到这道题目,首先想到的是暴力查找,即列举所有可能的子数组的加和,判断其加和是否为目标值k的整数倍,时间复杂度为O(n^2),尽管耗时较长,提交后发现竟然通过了。因此在这里再说一下暴力查找的思路:

  1. 首先是有两层for循环,外层循环表示当前的查找的子数组以哪个元素为开头,内层循环表示当前的查找以哪个元素为结尾;
  2. 计算当前子数组的加和,判断其是否是k的整数倍,是的话,则直接返回True,否则,继续查找。

一般对于时间复杂度O(n^2)的问题,需要尽量优化成时间复杂度O(nlogn)或者O(n),而这道题是有时间复杂度O(n)的解法的,这也是参考网上大神的解法的,其核心思路类似于问题leetcode-560-Subarray Sum Equals K(满足‘连续子数组加和等于目标值’的子数组个数) 思路与代码的解法。思路如下:

  1. 首先需要想到的是:如果整数A除以非零数值k的余数,与整数B除以非零数值k的余数相等,那么A与B的差一定能够被k整除;
  2. 需要一个字典数据结构m,用来记录余数相同的累加和是否出现过(这句话需要结合步骤3理解);
  3. 记录从数组开头截止到当前j位置的元素的累加和与k的余数,然后从字典m中查找是否已经出现过这样的累加和,假设在之前的i位置出现过,那么从i+1位置到j位置之间的子数组的加和一定能够被k整数,此时就满足题目的条件返回true,否则就将当前的余数写入到字典m中,继续循环即可。
  4. 需要注意k=0的情况。

问题解法

时间复杂度O(n^2)的解法代码如下:

def continuous_subarray_sum(nums, target):
    if not nums or len(nums) < 2:
        return False
    l = len(nums)
    for i in range(l - 1):
        tmp = nums[i]
        for j in range(i + 1, l):
            tmp += nums[j]
            if k == tmp:
                return True
            if k and not tmp % k:
                return True
    return False

时间复杂度O(n)的解法代码如下:

def continuous_subarray_sum(nums, target):
    if not nums or len(nums) < 2:
        return False
    l = len(nums)
    tmp = 0
    m = {0: -1}
    for i in range(l):
        tmp += nums[i]
        t = tmp % k if k else tmp
        if t in m:
            if i - m[t] > 1:
                return True
        else:
            m[t] = i
    return False

结合问题分析中的思路代码应该很容易理解。

你可能感兴趣的:(LeetCode,算法,数据结构)