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

前缀和技巧详解:和为 K、被 K 整除、连续数组及矩阵区域和

前缀和算法在四个经典力扣题目中的应用。包括和为 K 的子数组、和可被 k 整除的子数组、连续数组以及矩阵区域和。核心思路是利用哈希表记录前缀和及其出现次数或索引,将时间复杂度优化至 O(N)。对于二维矩阵问题,则采用二维前缀和预处理来快速计算区域和。代码示例提供 Java 实现。

SqlMaster发布于 2026/3/26更新于 2026/5/2924 浏览
前缀和技巧详解:和为 K、被 K 整除、连续数组及矩阵区域和

1. 和为 K 的子数组

题目链接:560. 和为 K 的子数组

算法思路:前缀和 + 哈希表

sum[i] 表示(0,i)之间的前缀和,当 x 为起始位置,i 元素结尾的数组和为 k 时,也就是相当于在(0,x)区间前缀和为 sum - k,因此也就是求出在(0,i-1)内有多少个前缀和为 sum - k 的数组即可。

但是也不需要真的定义一个前缀和,使用 sum 累加计算即可。前缀和处理的时机应该是遍历到哪个元素,就计算哪个元素之前的前缀和,因为当整个前缀和都预处理出来时,在哈希表中寻找可能会重复还未遍历到的元素的前缀和。

算法代码:

public int subarraySum(int[] nums, int k) {
    Map<Integer, Integer> hash = new HashMap<>();
    hash.put(0, 1);
    int sum = 0, ret = 0;
    for (int i = 0; i < nums.length; i++) {
        sum += nums[i];
        ret += hash.getOrDefault(sum - k, 0);
        hash.put(sum, hash.getOrDefault(sum, 0) + 1);
    }
    return ret;
}

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

题目链接:974. 和可被 k 整除的子数组

算法思路:前缀和 + 哈希表

该题和上道题基本类似,只不过用到了同余定理:(a - b) % k == 0 得到 a % k == b % k,该题也就是找在(0,i-1)区间内有多少个前缀和的余数为 sum[i] % k。

细节:前缀和中存的应该是前缀和的余数。

算法代码:

public int subarraysDivByK(int[] nums, int k) {
    Map<Integer, Integer> hash = new HashMap<>();
    hash.put(0, 1);
    int sum = 0, ret = 0;
    for (int i = 0; i < nums.length; i++) {
        sum += nums[i];
        int r = (sum % k + k) % k;
        ret += hash.getOrDefault(r, 0);
        hash.put(r, hash.getOrDefault(r, 0) + 1);
    }
    return ret;
}

3. 连续数组

题目链接:525. 连续数组

算法思路:前缀和 + 哈希表

该题可进行一个转换处理,那就是将元素 0 转换为 -1 处理,那么 0 和 1 数量相同的子数组就是 sum 和为 0 的数组,此时就和上面的查找和为 k 的数组基本一样了,就是找和为 0 的数组。

细节问题:

  • 此时哈希表中存的应该是 sum 和元素下标,因为该题返回的是数组长度。
  • 当遇到重复的 sum 时,不需要重复的将下标存入哈希表,因为返回最长的数组长度,当前面有下标存入时,当遇到重复的 sum,之前的下标一定小于现在的,因此可以跳过。
  • 计算长度,当计算长度时需要判断当前的结果是否大于之前的结果。
  • 还需要提前存入哈希表 0 的值的下标为 -1,因为当整个数组为 sum 时,会去 -1 的位置找 sum = 0,因此做提前处理。

算法代码:

public int findMaxLength(int[] nums) {
    Map<Integer, Integer> hash = new HashMap<>();
    hash.put(0, -1);
    int ret = 0, sum = 0;
    for (int i = 0; i < nums.length; i++) {
        if (nums[i] == 0) nums[i] = -1;
        sum += nums[i];
        if (hash.containsKey(sum)) ret = Math.max(ret, i - hash.get(sum));
        else hash.put(sum, i);
    }
    return ret;
}

4. 矩阵区域和

题目链接:1314. 矩阵区域和

题意,如图:

answer[i][j] 的值就是当前元素上下左右扩展 k 格的元素和。

算法思路:使用二维前缀和

首先预处理一个二维前缀和,和之前的二维前缀和定义相同。然后遍历元素计算该元素的 answer,但是注意细节,当 i-k,j-k 时可能会越界,此时需要使用边界 0,因此使用 Math.max 方法,也就是坐标为 Math.max(i-k,0);同样的 i+k 时也会越界,因此使用 min 即可。

还有细节问题要处理,就是前缀和定义时需要定义为 m+1 和 n+1,否则计算前缀和时边界问题会很麻烦,但是处理前缀和时对应的原数组的下标应该减一计算;同样的,当计算结果数组时,前缀和下标应该加一计算。

算法代码:

public int[][] matrixBlockSum(int[][] mat, int k) {
    int m = mat.length, n = mat[0].length;
    int[][] dp = new int[m + 1][n + 1];
    // 预处理前缀和
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + mat[i - 1][j - 1];
        }
    }
    // 使用前缀和
    int[][] ret = new int[m][n];
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            int x1 = Math.max(i - k, 0) + 1, y1 = Math.max(j - k, 0) + 1;
            int x2 = Math.min(i + k, m - 1) + 1, y2 = Math.min(j + k, n - 1) + 1;
            ret[i][j] = dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1];
        }
    }
    return ret;
}

目录

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

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

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

更多推荐文章

查看全部
  • Spring Boot 自动配置原理
  • VSCode 连接 Gitee 实现代码拉取与更新
  • 大模型 (LLMs) 私有化的三种方式:Prompts、Embeddings、Fine-tuning
  • AIGC 背景下图文内容社区数据指标体系构建指南
  • Claude Code AI 命令行工具安装使用与 MCP 配置指南
  • Python 数据分析与自动化 30 个实战技巧
  • MCP 工具速成:npx 与 uvx 全流程安装指南
  • AI 学术写作与查重工具功能解析
  • Spring Data JPA 原理与实战:Repository 接口深度解析
  • Distil-Whisper 快速入门:6 倍加速的语音识别方案
  • SkyWalking 多语言探针现状:.NET、C++ 与 Lua 实践指南
  • 学生成绩管理系统实战:AI 辅助开发全流程解析
  • 前端判断变量不为 null 和 undefined 的方法
  • 基于 LlamaFactory 微调 Qwen3.5-4B 模型实战
  • TCP 协议详解:报文格式、三次握手、滑动窗口与拥塞控制
  • OpenClaw 漏洞风险解析与 AI 代理日志审计指南
  • OpenClaw 架构原理与落地实战:AI Agent 执行网关底层逻辑
  • 鸿蒙双端协同:从手机游戏到 PC 大屏的无缝体验
  • 基于 FPGA 的 TDC 抖动测试系统设计
  • GitHub Copilot 学生认证流程与材料准备指南

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

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

  • Gemini 图片去水印

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