刷题(1) | 豆包MarsCode AI刷题

136 阅读3分钟

问题描述

小M是一个五年级的小学生,今天他学习了整除的知识,想通过一些练习来巩固自己的理解。他写下了一个长度为n的正整数序列 a_0,a_1,...,a_{n-1},然后想知道有多少个连续子序列的和能够被一个给定的正整数 b 整除。你能帮小M解决这个问题吗?

测试样例

样例1: 输入:n=3,b=3,sequence =[1,2,3] 输出:3

样例2: 输入:n=4,b=5,sequence=[5,10,15,20] 输出:10

样例3: 输入:n=5,b=2,sequence =[1,2,3,4,5] 输出:6

解题思路

给定序列中任意连续子序列之和

  • 定义前i个元素之和为pre_sum[i],因此,任意一个连续子序列之和为
sum(i,j)=pre_sum[j+1]pre_sum[i]sum(i,j)=pre\_sum[j+1]-pre\_sum[i]
  • 要使sum(i,j)能够被b整除,对公式进行变化可得
sum(i,j)%b==0(pre_sum[j+1]pre_sum[i])%b==0sum(i,j)\%b==0 → (pre\_sum[j+1]-pre\_sum[i])\%b==0
pre_sum[j+1]%b==pre_sum[i])%bpre\_sum[j+1]\%b==pre\_sum[i])\%b

字典查询

  • dict{}:通过key访问字典,当key不存在时,会引发keyError异常。
  • defaultdict():为字典提供一个默认值,当key不存在时,默认添加该keyint 对应 0str 对应 空字符串list 对应 [ ]。

统计同余的次数

  • 遍历整个序列,计算每前i个元素的序列和与b的模值,即pre_sum[i] % b
  • 使用哈希表(字典)count来记录每个模值出现的次数。
  • 当在位置i处遇到某个模值value时,意味着之前所有与value相同的模值对应的位置都可以形成一个满足条件的子序列。

计算结果

  • 对于每个模值value,如果它在前面已经出现过count[value]次,那么以当前位置为结束位置,并且和能被b整除的子序列的个数就增加了count[value]

算法流程

  • 初始化:

    • 创建一个defaultdict(int)类型的哈希表count,用于统计每个模值出现的次数。
    • count[0]初始化为1,可以推算,第一次模b=0时不需要配对。
  • 遍历序列并计算前i个元素的序列和:

    • 初始化pre_sum0,用于累加当前的前i个元素的序列和。
    • 初始化结果result0
  • 更新哈希表并计算结果:

    • 对于序列中的每个元素num

      • 更新前缀和:pre_sum += num
      • 计算当前前缀和的模值:value = pre_sum % b
      • count[value]累加到结果result中。
      • 更新count[value]的计数:count[value] += 1
  • 返回结果: 最终,result即为满足条件的连续子序列的个数。

代码实现

from collections import defaultdict

def solution(n, b, sequence):
    # 用字典记录 所有前i个连续子序列之和 对b的模值 出现的次数
    count = defaultdict(int)
    count[0] = 1  # 初始时,模为0的次数定义为1,可以自己推算
    pre_sum = 0
    result = 0
    
    for num in sequence:
        # 更新当前的序列和
        pre_sum += num
        # 当前序列和 模b 的值
        value = pre_sum % b
        
        # 计算当前模值出现的次数,说明有多少个子序列的和能被b整除
        result += count[value]
        
        # 更新value的出现次数
        count[value] += 1
    
    return result

if __name__ == "__main__":
    sequence = [1, 2, 3]
    print(solution(3, 3, sequence) == 3)

算法复杂度分析

  • 时间复杂度:

    • 算法主要遍历了一次序列,时间复杂度为O(n)
    • 在循环中,所有操作都是常数时间的。
    • 总时间复杂度: O(n)
  • 空间复杂度:

    • 使用了一个哈希表count,最坏情况下,模值的数量为b
    • 总空间复杂度: O(min(n, b))

总结

通过使用公式解析和和哈希表,将问题的复杂度降低到O(n)。算法利用了同余的性质,将连续子序列和能被b整除的问题,转换为序列和模值相等的问题。这样,我们只需统计序列和模值相同的次数,即可求出满足条件的子序列数量。