523 连续的子数组和(枚举、前缀和、哈希表)

1. 问题描述:

给你一个整数数组 nums 和一个整数 k ,编写一个函数来判断该数组是否含有同时满足下述条件的连续子数组:
子数组大小至少为 2 ,且子数组元素总和为 k 的倍数。如果存在,返回 true ;否则,返回 false 。如果存在一个整数 n ,令整数 x 符合 x = n * k ,则称 x 是 k 的一个倍数。0 始终视为 k 的一个倍数。

示例 1:

输入:nums = [23,2,4,6,7], k = 6
输出:true
解释:[2,4] 是一个大小为 2 的子数组,并且和为 6 。

示例 2:

输入:nums = [23,2,6,4,7], k = 6
输出:true
解释:[23, 2, 6, 4, 7] 是大小为 5 的子数组,并且和为 42 。 
42 是 6 的倍数,因为 42 = 7 * 6 且 7 是一个整数。

示例 3:

输入:nums = [23,2,6,4,7], k = 13
输出:false

提示:

1 <= nums.length <= 10 ^ 5
0 <= nums[i] <= 10 ^ 9
0 <= sum(nums[i]) <= 2 ^ 31 - 1
1 <= k <= 2 ^ 31 - 1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/continuous-subarray-sum

2. 思路分析:

对于这种题目我们首先考虑如何枚举才能将所有答案都枚举到,一般枚举的是以当前的i为终点..,对于这道题目来说我们可以枚举以当前的i为终点的所有区间和是否是k的倍数,计算某个区间的区间和我们可以使用前缀和,所以问题就转化为了判断以当前位置i结尾的所有区间的区间和是否是k的倍数,也即判断si - si-2, si - si-3...si - s0是否是k的倍数,进一步等价为si - 2,si - 3...s0除以k的余数是否等于si除以k的余数,如何快速判断之前是否存在一个数字呢?这里可以使用哈希表将之前的si-2个前缀和模k的余数存起来(边遍历边存储前缀和即可,哈希表优化技巧,与之前的前缀和 + 哈希表优化的题目也是类似的,需要判断判断某个数是否之前出现过),然后判断当前的si % k在哈希表中是否存在如果存在说明是满足条件的。(主要是如何枚举的思维然后如何分析得到当前问题问题的等价问题)

3. 代码如下:

from typing import List


class Solution:
    # 因为这里的k都是大于0的所以不用特判k=0的情况
    def checkSubarraySum(self, nums: List[int], k: int) -> bool:
        n = len(nums)
        s = [0] * (n + 1)
        # 前缀和
        for i in range(1, n + 1):
            s[i] += s[i - 1] + nums[i - 1]
        dic = dict()
        for i in range(2, n + 1):
            # 在循环中存储之前的前i-2项前缀和(要求前缀和长度大于等于2所以存储前i-2项)
            dic[s[i - 2] % k] = 1
            if s[i] % k in dic: return True
        return False
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值