跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
C++算法

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

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

蜜桃汽水发布于 2026/3/15更新于 2026/4/254 浏览
前缀和与哈希表实战:解决和为 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,则 a % k == b % k。 但在 C++ 中,负数取模的结果可能为负(例如 -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折了解详情
  • 💰 8折买阿里云服务器限时8折购买
  • 🦞 5分钟部署阿里云小龙虾了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • C++ 多容器非空检查的逻辑陷阱与最佳实践
  • 十分钟实战:使用 Supabase 构建商业级 AI 图像生成平台后端
  • 基于 OpenRouter 构建免费云端 AI 开发工作流
  • 光伏产品缺陷检测 AI 深度学习算法技术方案
  • Linux 文件描述符与重定向实战:从原理到 minishell 实现
  • Flutter 在 OpenHarmony 中集成 objectid 实现离线分布式 ID 生成
  • 现代 C++ 新特性 constexpr:从 C++11 到 C++20 的演进
  • 前端 Base64 格式文件上传详解:原理、实现与最佳实践
  • 前端错误监控与处理实战指南
  • Web 开发中五种常用加密算法原理与实战
  • AI 写作辅助平台深度评测:炼字工坊与蛙蛙写作
  • 主流 AI 生成 UI 设计工具盘点:支持可编辑源文件与代码导出
  • Vue3 + TypeScript:Promise<string> 转 string 类型错误解析与异步处理
  • 执行式 AI 数据交互核心语法:Agent 架构与实现
  • Rust WebAssembly 与 Three.js 结合的高性能 3D 粒子系统实战
  • 普通产品经理转型 AI 产品经理:必备准备与技能提升
  • YOLO26-Pose 零样本姿态估计:从原理到机器人应用
  • Python 语言学习:大学生学术与职业应用指南
  • Python 读取文件夹文件名提取金额并计算总和
  • Edge 边栏 Copilot 图标消失的修复方案

相关免费在线工具

  • 加密/解密文本

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