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

前缀和与哈希表实战:解决和为 K 及整除子数组问题

前缀和配合哈希表可将子数组统计问题的时间复杂度优化至 O(n)。针对和为 K 的子数组,利用 sum[i] - sum[x-1] = k 的关系查找历史前缀和;针对和可被 K 整除的子数组,需应用同余定理,并通过 (sum % k + k) % k 统一处理负数取模问题。两者均通过维护前缀和频次表实现高效查询,是面试中的高频考点。

蜜桃汽水发布于 2026/3/15更新于 2026/6/1123 浏览
前缀和与哈希表实战:解决和为 K 及整除子数组问题

前缀和专题实战

在子数组统计类问题中,暴力枚举往往会导致 O(n^2) 的时间复杂度。引入前缀和(Prefix Sum)配合哈希表,可以将查询效率优化至 O(1),从而将整体复杂度降为 O(n)。这里我们结合两道经典题目,深入探讨这一技巧的应用细节。

1. 和为 K 的子数组

题目核心: 给定一个整数数组和一个整数 k,找到该数组中和为 k 的连续子数组的个数。

思路解析: 假设当前遍历到位置 i,前缀和为 sum[i]。如果存在某个起始位置 x,使得区间 [x, i] 的和为 k,那么必然满足: sum[i] - sum[x-1] = k 即: sum[x-1] = sum[i] - k

这意味着,我们只需要在遍历过程中,记录之前出现过的每一个前缀和及其次数。当计算到当前位置的前缀和时,直接去哈希表中查找 sum[i] - k 出现的次数即可累加结果。

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

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int, int> hash;
        // 初始化:前缀和为 0 的情况出现一次
        hash[0] = 1; 
        int n = nums.size();
        int sum = 0, ret = 0;
        
        for (auto x : nums) {
            sum += x;
            // 如果之前出现过 sum - k,说明存在以当前位置结尾、和为 k 的子数组
            if (hash.count(sum - k)) {
                ret += hash[sum - k];
            }
            // 更新当前前缀和的出现次数
            hash[sum]++;
        }
        return ret;
    }
};

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

题目核心: 给定一个整数数组和一个整数 k,返回该数组中和可被 k 整除的非空连续子数组的数目。

前置知识: 这道题是上一题的变体,关键在于处理负数取模。 根据同余定理,若 (a - b) % k == 0,则 。 但在 C++ 中,负数取模的结果可能为负(例如 ),而数学上的同余要求余数非负。因此需要统一处理公式:。

a % k == b % k
-1 % 3 = -1
(a % k + k) % k

思路解析: 逻辑与前题类似,只是判断条件变为余数相等。 设当前前缀和为 sum,我们需要找之前有多少个前缀和 prev_sum 满足 (sum - prev_sum) % k == 0。 这等价于 sum % k == prev_sum % k。 为了兼容负数,我们在存入哈希表和查询时都使用 (sum % k + k) % k 作为键。

代码实现: 注意 hash[0%k] = 1 的初始化,以及取模时的正数化处理。

class Solution {
public:
    int subarraysDivByK(vector<int>& nums, int k) {
        unordered_map<int, int> hash;
        // 初始前缀和为 0,其模 k 余数为 0
        hash[0] = 1; 
        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;
    }
};

总结

这两道题展示了前缀和与哈希表的经典组合。第一题关注差值匹配,第二题关注同余关系。特别是第二题中,务必注意编程语言对负数取模的处理差异,通过 (val % k + k) % k 这种写法可以安全地保证余数始终为正,避免边界错误。时间复杂度均为 O(n),空间复杂度为 O(min(n, k))。

目录

  1. 前缀和专题实战
  2. 1. 和为 K 的子数组
  3. 2. 和可被 K 整除的子数组
  4. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • C++ 核心基础概念解析
  • Cloudflare 反爬绕过:Canvas/WebGL/WebRTC 多维度指纹隐身方案
  • Clawdbot 部署指南:反向代理与 WebAuth 配置
  • Web3 基于区块链的下一代互联网
  • 大模型选型避坑指南:AI Ping 性能评测与实战建议
  • Agent-Browser:面向 AI 的浏览器自动化 CLI 工具
  • 2024 检索增强生成(RAG)技术综述:基础、增强与应用
  • C# 通过 HTTP API 集成 GLM-4.6V-Flash-WEB 模型实战
  • C++ 容器适配器与核心数据结构精解:栈、队列、deque 底层实现与实战应用
  • 时序数据库选型指南:Apache IoTDB 工业物联网应用实践
  • Windows 安装原生 Codex CLI 配置 AI 代码助手
  • 大模型微调技术详解与实战代码实现
  • Ubuntu 20.04 云服务器手动安装 Oracle JDK 17 指南
  • WSL 配置与 cpolar 内网穿透实现公网访问服务
  • MySQL 安装后出现无法连接远程主机 catalog 下载失败错误解决
  • Ubuntu 安装 Node.js 指定版本指南
  • GitHub 7 款 Claude Skills 开源项目:Skill Creator、Superpowers 与 Code Review 实战指南
  • OpenCLIP 开源实现与训练实战指南
  • Android 大厂面试真题与核心知识点解析
  • ComfyUI 运行 Wan 2.1 工作流:生成电影级视频(兼容 Mac/Windows)

相关免费在线工具

  • 加密/解密文本

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