AI刷题之连续字串和的整除问题 | 豆包MarsCode AI刷题

104 阅读3分钟

“连续字串和的整除问题”题目要求

一、问题描述

小M是一个五年级的小学生,今天他学习了整除的知识,想通过一些练习来巩固自己的理解。他写下了一个长度为 n 的正整数序列 a_0, a_1, ..., a_{n-1},然后想知道有多少个连续子序列的和能够被一个给定的正整数 b 整除。你能帮小M解决这个问题吗? 例如对于[123, 456, 789],14个符合条件的数为:147 149 158 167 169 248 257 259 268 347 349 358 367 369

二、测试样例

样例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


三、题目解析

3.1代码思路

  1. 前缀和计算:前缀和数组 prefixSum 记录从序列开始到当前位置的和。例如,prefixSum[i] 表示 a[0] + a[1] + ... + a[i]。我们可以使用哈希表来记录前缀和的余数出现的次数。如果两个前缀和的余数相同,那么它们之间的子序列和可以被 b 整除。
  2. 余数计算:对于每个前缀和,利用int remainder = prefixSum % b; 计算其对 b 的余数,并记录在哈希表中。其中,如果余数为负数,则转变为正数,方便代码实现。
  3. 统计结果:利用if (remainder == 0) count++; 和 count += remainderCount.get(remainder);来统计结果,如果余数为零则计数累加。
  4. 更新哈希表:可以使用哈希表来记录前缀和的余数出现的次数。如果两个前缀和的余数相同,那么它们之间的子序列和可以被 b 整除。此方法通过remainderCount.put(remainder, remainderCount.getOrDefault(remainder, 0) + 1);来实现,

3.2详细代码

import java.util.List;
import java.util.ArrayList; // 添加这一行

public class Main {
    public static int solution(int n, int b, List<Integer> sequence) {
        // 创建一个哈希表来记录前缀和的余数出现的次数
        HashMap<Integer, Integer> remainderCount = new HashMap<>();
        // 初始化前缀和为0,余数为0的情况
        int prefixSum = 0;
        int count = 0;
        
        // 遍历序列
        for (int i = 0; i < n; i++) {
            // 计算当前前缀和
            prefixSum += sequence.get(i);
            // 计算当前前缀和的余数
            int remainder = prefixSum % b;
            
            // 如果余数为负数,调整为正数
            if (remainder < 0) {
                remainder += b;
            }
            
            // 如果余数为0,说明从开始到当前位置的子序列和可以被b整除
            if (remainder == 0) {
                count++;
            }
            
            // 如果哈希表中已经存在相同的余数,说明存在一个子序列的和可以被b整除
            if (remainderCount.containsKey(remainder)) {
                count += remainderCount.get(remainder);
            }
            
            // 更新哈希表中余数的计数
            remainderCount.put(remainder, remainderCount.getOrDefault(remainder, 0) + 1);
        }
        
        return count;
    }

    public static void main(String[] args) {
        // 测试用例
        List<Integer> sequence = new ArrayList<>();
        sequence.add(1);
        sequence.add(2);
        sequence.add(3);
        System.out.println(solution(3, 3, sequence) == 3);
    }
}

四、知识总结

本题目主要使用了哈希表来解决问题。使用哈希表在这个问题中是一个非常有效的策略,又如下几点原因:

4.1. 快速查找和插入

哈希表提供了平均时间复杂度为 O(1) 的查找和插入操作。这意味着我们可以快速地检查某个余数是否已经出现过,并且可以快速地更新余数的计数。

4.2. 记录前缀和的余数

我们需要记录每个前缀和的余数,以便在后续的遍历中能够快速判断是否存在一个子序列的和可以被 b 整除。通过哈希表,我们可以轻松地记录每个余数的出现次数。

4.3. 统计子序列的数量

如果两个前缀和的余数相同,那么它们之间的子序列和可以被 b 整除。通过哈希表,我们可以快速统计这些子序列的数量