跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

前缀和算法实战:和为 K 的子数组与和可被 K 整除的子数组

前缀和结合哈希表解决子数组求和问题。针对和为 K 的子数组,通过记录前缀和出现次数快速定位目标区间;对于和可被 K 整除的子数组,利用同余定理处理负数取模情况,统计相同余数的频次。两题均将时间复杂度优化至 O(n),是面试高频考点。

路由之心发布于 2026/3/29更新于 2026/10/1984 浏览
前缀和算法实战:和为 K 的子数组与和可被 K 整除的子数组

29. 和为 K 的子数组

题目描述

给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续子数组的个数。

示例

输入:nums = [1,1,1], k = 2 输出:2 解释:[1,1] (索引 0-1) 和 [1,1] (索引 1-2)

解法:前缀和 + 哈希表

核心思路

设 i 为数组中的任意位置,用 sum[i] 表示区间 [0, i] 内所有元素的和。要计算以 i 结尾且和为 k 的子数组数量,本质是寻找起始位置 x,使得区间 [x, i] 的和等于 k。

根据前缀和定义: sum[x, i] = sum[0, i] - sum[0, x-1] = k 即:sum[0, x-1] = sum[0, i] - k

这意味着我们只需要在遍历到 i 时,统计之前有多少个前缀和等于当前前缀和减去 k。无需维护完整的前缀和数组,使用哈希表记录每种前缀和出现的次数即可。

C++ 实现

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int, int> hash;
        hash[0] = 1; // 初始化,处理从下标 0 开始的子数组
        int count = 0;
        int sum = 0;
        
        for(int i = 0; i < nums.size(); i++) {
            sum += nums[i];
            if(hash.count(sum - k)) {
                count += hash[sum - k];
            }
            hash[sum]++;
        }
        return count;
    }
};

30. 和可被 K 整除的子数组

题目描述

给定一个整数数组 A,返回其中元素之和可被 K 整除的非空连续子数组的数目。

示例

输入:A = [4,5,0,-2,-3,1], K = 5 输出:7 解释:有 7 个子数组满足条件。

前置知识:同余定理与负数取模

同余定理

如果 (a - b) % n == 0,则 a % n == b % n。通俗来说,若两数之差能被 n 整除,则它们对 n 取模的结果相同。

负数取模处理

C++ 中负数取模结果可能为负(例如 -1 % 3 = -1)。为了保证余数为正,统一采用 (a % n + n) % n 的形式修正。

解法:前缀和 + 哈希表

核心思路

思路与上一题类似,但判断条件变为子数组和能否被 k 整除。 设 [0, i] 的前缀和为 b,[0, x-1] 的前缀和为 a。若 [x, i] 的和能被 k 整除,则 (b - a) % k == 0。 根据同余定理,这等价于 b % k == a % k。

因此,问题转化为:统计之前有多少个前缀和的余数与当前前缀和的余数相同。同样使用哈希表存储余数出现的频次。

C++ 实现

class Solution {
public:
    int subarraysDivByK(vector<int>& nums, int k) {
        unordered_map<int, int> hash;
        hash[0] = 1; // 余数为 0 的情况初始化为 1
        int count = 0;
        int sum = 0;
        int rem = 0;
        
        for(auto i : nums) {
            sum += i;
            rem = sum % k;
            // 修正负数取模结果
            if(rem < 0) {
                rem += k;
            }
            
            if(hash.count(rem)) {
                count += hash[rem];
            }
            hash[rem]++;
        }
        return count;
    }
};

总结

两道题均利用前缀和将区间和问题转化为查找问题,配合哈希表将时间复杂度优化至 O(n)。第二题的关键在于理解同余定理并正确处理负数取模场景。掌握这一模式,能高效解决大量涉及子数组求和的变体问题。

目录

  1. 29. 和为 K 的子数组
  2. 题目描述
  3. 示例
  4. 解法:前缀和 + 哈希表
  5. 核心思路
  6. C++ 实现
  7. 30. 和可被 K 整除的子数组
  8. 题目描述
  9. 示例
  10. 前置知识:同余定理与负数取模
  11. 同余定理
  12. 负数取模处理
  13. 解法:前缀和 + 哈希表
  14. 核心思路
  15. C++ 实现
  16. 总结

更多推荐文章

查看全部
  • C/C++ 动态规划入门:多状态 DP 实战(打家劫舍与股票买卖)
  • C++ 从入门到精通:完整实战指南
  • Linux 缓冲区和文件系统
  • AI 绘画提示词风控:Qwen3Guard-Gen-8B 前置审核实战
  • MCP Server 实现 Excel 表格一键生成可视化图表 HTML 报告
  • 文心一言 4.5 开源模型深度解析:轻量化部署与中文专精
  • OpenClaw 助手 20 个精选 Skills 配置与实战指南
  • WebPShop 插件:让 Photoshop 完美支持 WebP 格式
  • Python 50 道核心面试题:从基础到高级实战解析
  • Protobuf、JSON、XML 核心对比与 C++ 实现
  • 使用 gpt-oss-20b-WEBUI 快速搭建本地 AI 对话系统
  • DeepSeek 深度使用指南:提示词技巧与本地知识库搭建
  • 小米智能家居 Miloco 分离式部署指南
  • Python 数据统计指南:从基础配置到高级分析
  • VSCode 远程连接 Linux 配置:离线安装与免密登录
  • Rust 核心基础数据类型与变量系统
  • MySQL 数据表删除:DROP 与 TRUNCATE 实战指南
  • 人工智能:自然语言处理在医疗健康领域的应用与实战
  • Linux 进程池实战:基于管道通信的任务分发系统实现
  • VRCT 智能翻译工具:解决 VRChat 跨语言交流问题

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online