LC523:连续的子数组和(中等-数学-前缀和 哈希表)

523. 连续的子数组和

题目:给你一个整数数组 nums 和一个整数 k ,编写一个函数来判断该数组是否含有同时满足下述条件的连续子数组:子数组大小 至少为 2 ,且子数组元素总和为 k 的倍数。 如果存在,返回 true ;否则,返回 false 。(小坑0是任意数的倍数)

思考过程:

想法一:暴力

           双层循环加判断,复杂度为O(n^3)超时。

想法二:动态规划

           d[i][j]表示第i个元素到第j个元素的和,计算过程中判断。复杂度为O(n^2)超时。

想法三:前缀和 + 哈希表法
    ① 首先为了方便计算连续子数组的和,我们可以计算一下前缀和。如:
        下标       0   1  2  3  4                                       [-1]   0   1   2   3   4      
        nums     23 2  4  6  7      preSum(前缀和)   [ 0]  23 25 29 35 41

        可知连续子数组[i:j]的和num[i:j] =  preSum[j-1] - preSum[i-1],如:nums[2:4] = nums[2]+nums[3] = preSum[3] - preSum[1]。考虑当i等于0时候 要计算num[0:j] = preSum[j-1] - preSum[-1] 需要设置preSum[-1]=0(可在初始化时完成)。

   ② 知道了连续子数组的和,但是要满足两个条件:i)j-i>=2(注意nums[i:j]是左闭右开的)代表i j-1不是同一个元素  2) num[i:j] % k == 0(代表是k的倍数)。
      根据条件二 num[i:j] % k == 0 则(preSum[j-1] - preSum[i-1])% k == 0 即 preSum[j-1] % k = preSum[i-1]% k,那么现在主要任务转移为计算preSum[x] % k(x的范围是-1到n-1),并判断preSum[i] %k 和 preSum[j] %k 在满足条件j-i>=2的情况下是否相等。可通过哈希表来实现:

      如果不在哈希表中:

                添加  preSum[x] %k为key,对应下标为value到哈希表中。

      如果在哈希表中并且满足在哈希表中对应元素的下标和遍历时候的下标满足 j-i>=2的关系,则返回True。如下述情况返回true :

                               -1 0  1  2  3  4
          preSum % k   0 2  4  1  0  6                                有两个0存在,且3-(-1)>=2

      ps:①初始化 preSum[-1]=0 ,可以直接添加到哈希表中

代码:

def checkSubarraySum(nums, k):
    n, hs, preSum = len(nums), {0: -1}, 0

    for i in range(n):
        preSum += nums[i]
        if (preSum % k) in hs:  # 当 preSum % k 在字典里
            # 如果在字典里 要满足 中间隔一个元素  即 i - hs[preSum % k] >= 2
            if i - hs[preSum % k] >= 2:
                return True
            # 在字典里 但是不满足上述要求的  不做操作(不会添加到里边)
        else:  # 当 preSum % k 不在字典里
            hs[preSum % k] = i
    return False

自己犯的一个错误,我将条件 (preSum % k) in hs 和 i - hs[preSum % k] >= 2合并后,后边的else没变,导致犯错!!!大家写的时候要注意下

知识点:

  哈希表用字典来模拟。

 初始化: hs = dict()   ; hs = {a:b}

 添加元素: hs[c] = d

 得到对应key的value: v2 =  hs.get(key1,value1)  (如果key1在hs中,返回对应的value,如果不在,返回value1)

 

 

路虽远,行则将至。事虽难,做则必成 。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值