给定一个包含非负数的数组和一个目标整数 k,编写一个函数来判断该数组是否含有连续的子数组,其大小至少为 2,总和为 k 的倍数,即总和为 n*k,其中 n 也是一个整数。
示例 1:
输入: [23,2,4,6,7], k = 6
输出: True
解释: [2,4] 是一个大小为 2 的子数组,并且和为 6。
示例 2:
输入: [23,2,6,4,7], k = 6
输出: True
解释: [23,2,6,4,7]是大小为 5 的子数组,并且和为 42。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/continuous-subarray-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
——————————
解题思路:
(1)维护一个数组copy_nums,数组中的每个值copy_nums[i]是nums[0]到nums[i]的总和。这样可以通过两次循环遍历copy_nums中两两数据之间的差值是否是k的倍数。
class Solution:
def checkSubarraySum(self, nums: List[int], k: int) -> bool:
length = len(nums)
if length <=1:
return False
copy_nums = nums[:] # 首先对原数组进行复制
for i in range(1,length): # 计算从nums[0]到nums[i]的累加和
copy_nums[i] += copy_nums[i-1]
for i in range(length-1):
for j in range(i+1,length):
ans = nums[i] + copy_nums[j] - copy_nums[i] # 比较数组中两两之间的差值是否是k或者k的倍数
if k==ans or (k!=0 and ans%k==0):
return True
return False
(2)可以知道,当数组中存在连续子数组的和等于k或者k的倍数,假设为nums[i]到nums[j]之间的子数组,那么可以知道sum[i-1]%k==sum[j]%k,其中sum[i-1]是nums数组中前i-1个值之和,sum[j]是nums数组中前j个值之和。因为nums[i]到nums[j]的和为k的倍数。所以我们可以从数组第一个数据开始,计算前i个数据之和和k的余数,如果sum[i]%k == sum[j]%k,同时j-i>1,则数组中存在这样的连续子数组之和是k的倍数。
class Solution:
def checkSubarraySum(self, nums: List[int], k: int) -> bool:
if k==0: # 当k的值为0,数组中元素都是非负的,要是条件成立,数组中必须存在两个连续的0值。
for i in range(len(nums)-1):
if nums[i] + nums[i+1] == 0:
return True
return False
res = 0
dicts = {} # 创建一个字典,字典的key是余数,value是对应的位置索引
dicts[0] = -1 # 创建起始点,位置为-1,与k的余数为0,这里很重要
for index,num in enumerate(nums):
ans = (num + res) % k
res = ans
if ans in dicts.keys(): # 当找到两部分余数是一样的,同时两者之间的索引差大于1时,则返回True
if index - dicts[ans] > 1:
return True
dicts.setdefault(ans,index) # 如果字典中不存在这余数,则创建一个余数
return False