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

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

针对子数组求和与整除问题,采用前缀和配合哈希表可将时间复杂度优化至 O(n)。核心思路是遍历数组计算当前前缀和,查询哈希表中是否存在满足条件的前缀和差值或余数。对于整除问题,需特别注意负数取模的处理,使用 (sum % k + k) % k 保证结果非负。该方法避免了暴力枚举,显著提升了效率。

孤勇者发布于 2026/3/26更新于 2026/7/729 浏览
前缀和技巧实战:和为 K 的子数组与和可被 K 整除的子数组

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

在算法面试中,子数组求和问题非常常见。如果直接暴力枚举所有子数组,时间复杂度会达到 O(n²) 甚至更高。利用前缀和(Prefix Sum)结合哈希表,我们可以将这类问题的时间复杂度优化至 O(n)。本文将通过 LeetCode 560 和 974 两道经典题目,深入讲解这一核心技巧。

560. 和为 K 的子数组

题目链接: LeetCode 560

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

文章配图

解题思路: 设 sum[i] 表示从索引 0 到 i 的所有元素之和。如果我们想知道以位置 i 结尾、和为 k 的子数组有多少个,本质上就是寻找有多少个起始位置 x,使得 sum[i] - sum[x-1] = k。移项后得到 sum[x-1] = sum[i] - k。

这意味着,我们不需要维护一个完整的前缀和数组,只需要在遍历过程中,用一个哈希表记录当前前缀和出现的次数。对于每一个当前位置的前缀和 currentSum,我们只需查询哈希表中是否存在 currentSum - k,如果存在,说明之前有若干次前缀和满足条件,累加其出现次数即可。

注意初始化时 hash[0] = 1,这代表前缀和为 0 的情况(即从数组开头开始的子数组)。

参考实现:

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

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

题目链接: LeetCode 974

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

文章配图

解题思路: 这道题是上一题的变体,核心在于判断子数组和是否能被 K 整除。根据同余定理,如果 (b - a) % K == 0,则 b % K == a % K。也就是说,如果两个前缀和对 K 取模的结果相同,那么它们之间的差值(即中间那段子数组的和)一定能被 K 整除。

因此,我们需要统计的是前缀和模 K 的余数。这里有一个关键点:负数取模。在 C++ 中,负数取模可能得到负数结果(例如 -1 % 3 = -1)。为了保证余数非负且符合数学定义,统一使用公式 (sum % K + K) % K 来处理。

同样地,使用哈希表记录每个余数出现的次数。当计算当前前缀和的余数 r 时,若哈希表中已存在 r,则说明之前有若干次前缀和与当前前缀和同余,累加对应的次数。

前置知识补充:

  • 同余定理: 若 (a - b) % n == 0,则 a % n == b % n。
  • 负数取模处理: 使用 (a % n + n) % n 确保结果始终为正。

参考实现:

class Solution {
public:
    int subarraysDivByK(vector<int>& nums, int k) {
        unordered_map<int, int> hash;
        hash[0] = 1; // 初始前缀和为 0,余数为 0
        int sum = 0, ret = 0;
        for (auto x : nums) {
            sum += x;
            // 处理负数取模,保证余数在 [0, k-1] 范围内
            int r = (sum % k + k) % k;
            if (hash.count(r)) {
                ret += hash[r];
            }
            hash[r]++;
        }
        return ret;
    }
};

总结

这两道题展示了前缀和配合哈希表的强大之处。通过将空间换时间,我们将原本需要 O(n²) 的枚举过程优化到了 O(n)。在处理整除问题时,务必注意编程语言对负数取模的定义差异,通过统一的数学公式规避潜在 Bug。掌握这一模式,能高效解决大量涉及区间和统计的问题。

目录

  1. 前缀和技巧实战:和为 K 的子数组与和可被 K 整除的子数组
  2. 560. 和为 K 的子数组
  3. 974. 和可被 K 整除的子数组
  4. 总结
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • PGvector 在 Spring AI 中实现向量数据库存储与相似性搜索
  • 打造 AI 产品经理:关键技能与入门指导
  • 使用 Spring Session 配合 Redis 管理 HTTP Session
  • CentOS 7 安装 JDK 8(jdk-8u461-linux-x64)教程
  • Flutter 三方库 xpath_selector 在鸿蒙系统的适配与应用
  • Spring Cloud Gateway 统一服务入口实战指南
  • 生产环境中使用 git revert 的 5 个真实案例
  • 数据结构:八种常见排序算法详解
  • 数据结构:栈与队列
  • Java Graphics2D 基础图形绘制详解
  • DALL·E 3 绘图功能与 API 使用指南
  • OpenCLAW Linux 部署与配置实战指南
  • 汇川 RobotLab 软件常规操作指南
  • 鸿蒙电商购物车全栈实战:用户管理、商品列表与购物车实现
  • 哈希表数据结构原理与经典算法题解析
  • 微信小程序基础组件概览
  • MySQL 动态分区管理:自动化与优化实践
  • GLPI 开源 IT 资产管理系统安装指南
  • C++ 异常处理机制:捕获、自定义与实战
  • OpenAI DALL·E API 调用与 AI 绘画应用开发实战

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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