青训营刷题日记 | 豆包MarsCode AI 刷题

47 阅读2分钟

今天我尝试连续子串和的整除问题:小M是一个五年级的小学生,今天他学习了整除的知识,想通过一些练习来巩固自己的理解。他写下了一个长度为 n 的正整数序列 a_0, a_1, ..., a_{n-1},然后想知道有多少个连续子序列的和能够被一个给定的正整数 b 整除。 首先要解决这个问题,我们需要找出所有连续子序列的和,并计算其中可以被给定的正整数 ( b ) 整除的子序列的数量。为了提高效率,我们可以利用前缀和的概念和哈希表来快速计算子序列的和。

思路

  1. 前缀和:通过维护一个前缀和数组,可以快速计算任意子序列的和。
  2. 取模:对于任意两个前缀和,如果它们的差值可以被 ( b ) 整除,则这两个前缀和对应的子序列和也可以被 ( b ) 整除。
  3. 哈希表:使用哈希表记录前缀和的模 ( b ) 的出现次数。这样在遍历过程中可以快速查询已有的前缀和的模值。

以下是代码实现:

def solution(n, b, sequence):
    # 前缀和
    prefix_sum = 0
    count = 0
    # 记录前缀和模 b 的次数
    mod_count = {0: 1}  # mod 0 出现 1 次(代表前缀和为0的情况)

    for num in sequence:
        prefix_sum += num
        mod_value = prefix_sum % b
        
        # 由于 Python 的 % 可能返回负值,我们需要调整它为非负
        if mod_value < 0:
            mod_value += b
        
        # 如果这个模值已经在 map 中,说明有多少个前缀和的差为 b 的倍数
        if mod_value in mod_count:
            count += mod_count[mod_value]
        
        # 更新 map 中这个模值的出现次数
        if mod_value in mod_count:
            mod_count[mod_value] += 1
        else:
            mod_count[mod_value] = 1

    return count

if __name__ == "__main__":
    # 测试用例
    print(solution(3, 3, [1, 2, 3]) == 3)
    print(solution(4, 5, [5, 10, 15, 20]) == 10)
    print(solution(5, 2, [1, 2, 3, 4, 5]) == 6)

代码解释

  1. 前缀和:在每次迭代中,累加当前数字到 prefix_sum 中。
  2. 模值:计算当前前缀和对 ( b ) 的模值。
  3. 哈希表:检查当前模值是否已经存在于哈希表中。如果存在,说明之前有相同模值的前缀和,这意味着存在子序列和可以被 ( b ) 整除。
  4. 更新次数:在每次更新模值出现次数后,也更新到哈希表中。

这个算法的时间复杂度为 ( O(n) ),能够高效地解决问题。

今天的实验给了我很多收获和思考的空间。在实际操作过程中,我深刻感受到设计不仅仅是一个技术性的任务,更是一门将实际业务需求转化为系统逻辑的艺术。每一个设计决策都需要在复杂的业务背景下平衡效率、完整性和未来扩展的可能性。