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

前缀和算法详解:连续数组与矩阵区域和

讲解前缀和算法在两个经典问题中的应用。第一题连续数组,通过将 0 视为 -1 转化为寻找和为 0 的子数组,利用哈希表记录前缀和首次出现位置,实现 O(n) 时间复杂度的求解。第二题矩阵区域和,采用二维前缀和技术,通过预处理前缀和矩阵,结合边界处理计算任意矩形区域的和,同样达到线性时间复杂度。文章提供了 C++ 和 Java 两种语言的完整代码实现及复杂度分析。

KernelLab发布于 2026/2/6更新于 2026/7/2139 浏览
前缀和算法详解:连续数组与矩阵区域和

031 连续数组

题目描述:

文章配图

1.1 解法一:暴力解法

暴力解法就是枚举所有的子数组,然后判断子数组是否满足要求。

1.2 解法二:前缀和在哈希表中

将 0 记为 -1,1 记为 1,问题就变成了找出一段区间,这段区间的和等于 0。于是,这道题就和【和为 K 的子数组】的思路一样了。

文章配图

设 i 为数组中的任意位置,用 sum[i] 表示 [0, i] 区间中的所有元素的和。

想知道最大的以 i 结尾的和为 0 的子数组,就要找到从左往右第一个 x1 使得 [x1, i] 区间内的所有元素的和为 0。那么 [0, x1 - 1] 区间内的和是不是就是 sum[i] 了。于是这个问题就变成了——

找到在 [0, i - 1] 区间内,第一次出现 sum[i] 的位置即可。

我们不用真的初始化一个前缀和数组,因为我们只关心在 i 位置之前,第一个前缀和等于 sum[i] 的位置。因此,我们仅需用一个哈希表,一边求当前位置的前缀和,一边记录第一次出现该前缀和的位置。

1.3 算法实现

1.3.1 C++ 实现
class Solution { 
public: 
    int findMaxLength(vector<int>& nums) { 
        unordered_map <int,int> hash; // 创建哈希,统计前缀和出现的位置 
        hash[0] = -1; // 默认有一个前缀和为 0 的情况 
        int sum = 0, ret = 0; // ret 标记最终长度 
        for(int i = 0; i < nums.size(); ++i) { 
            sum += nums[i] == 0 ? -1 : 1; // 三目表达式判断一下,是 0 就 -1 
            (hash.(sum)) { 
                ret = (ret, i - hash[sum]); 
            }  { 
                hash[sum] = i; 
            } 
        } 
         ret; 
    } 
};
if
count
// 存在:如果找到 sum,说明此时 hash[sum] 里面存了前面那个的下标
max
// 更新长度,i - j 即可
else
// 记录第一次出现的位置
return

时间复杂度:O(n),空间复杂度:O(n)。

文章配图

1.3.2 Java 实现
class Solution { 
    public int findMaxLength(int[] nums) { 
        Map<Integer, Integer> hash = new HashMap<Integer, Integer>(); 
        hash.put(0, -1); // 默认存在一个前缀和为 0 的情况 
        int sum = 0, ret = 0; 
        for (int i = 0; i < nums.length; i++) { 
            sum += (nums[i] == 0 ? -1 : 1); // 计算当前位置的前缀和 
            if (hash.containsKey(sum)) ret = Math.max(ret, i - hash.get(sum)); 
            else hash.put(sum, i); 
        } 
        return ret; 
    } 
}

时间复杂度:O(n),空间复杂度:O(n)。

文章配图

032 矩阵区域和

题目描述:

文章配图

2.1 算法思路:二维前缀和

二维前缀和的简单应用题,关键就是我们在填写结果矩阵的时候,要找到原矩阵对应区域的【左上角】以及【右下角】的坐标。

(1)左上角坐标:x1 = i - k,y1 = j - k,但是由于会「超过矩阵」的范围,因此需要对 0 取一个 max。因此修正后的坐标为:x1 = max(0, i - k),y1 = max(0, j - k);

(2)右下角坐标:x2 = i + k,y2 = j + k,但是由于会【超过矩阵】的范围,因此需要对 m - 1,以及 n - 1 取一个 min。因此修正后的坐标为:x2 = min(m - 1, i + k),y2 = min(n - 1, j + k)。

文章配图

然后将求出来的坐标代入到【二维前缀和矩阵】的计算公式上即可,注意下标的映射关系。

2.2 算法实现

2.2.1 C++ 实现
class Solution { 
public: 
    vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) { 
        int m = mat.size(), n = mat[0].size(); // 行和列 
        // 1、预处理一个前缀和矩阵 
        vector<vector<int>> dp(m + 1, vector<int>(n + 1)); // 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]; 
        // 2、使用前缀和矩阵 
        vector<vector<int>> ret(m, vector<int>(n)); // 跟原始矩阵同等规模 
        for(int i = 0; i < m; i++) 
            for(int j = 0; j < n; j++) { 
                int x1 = max(0, i - k) + 1, y1 = max(0, j - k) + 1; // +1 就是为了在 dp 表里面直接可以找到 
                int x2 = min(m - 1, i + k) + 1, y2 = min(n - 1, j + k) + 1; 
                ret[i][j] = dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1]; 
            } 
        return ret; 
    } 
};

时间复杂度:O(mn),空间复杂度:O(mn)。

文章配图

2.2.2 Java 实现
class Solution { 
    public int[][] matrixBlockSum(int[][] mat, int k) { 
        int m = mat.length, n = mat[0].length; 
        // 1、预处理前缀和矩阵 
        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]; 
        // 2、使用 
        int[][] ret = new int[m][n]; 
        for (int i = 0; i < m; i++) 
            for (int j = 0; j < n; j++) { 
                int x1 = Math.max(0, i - k) + 1, y1 = Math.max(0, j - k) + 1; 
                int x2 = Math.min(m - 1, i + k) + 1, y2 = Math.min(n - 1, j + k) + 1; 
                ret[i][j] = dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1]; 
            } 
        return ret; 
    } 
}

时间复杂度:O(mn),空间复杂度:O(mn)。

文章配图

目录

  1. 031 连续数组
  2. 1.1 解法一:暴力解法
  3. 1.2 解法二:前缀和在哈希表中
  4. 1.3 算法实现
  5. 1.3.1 C++ 实现
  6. 1.3.2 Java 实现
  7. 032 矩阵区域和
  8. 2.1 算法思路:二维前缀和
  9. 2.2 算法实现
  10. 2.2.1 C++ 实现
  11. 2.2.2 Java 实现
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • AIGC 背景下图文内容社区数据指标体系构建指南
  • 仓颉语言 MVVM 架构实现与现代 UI 最佳实践
  • 鸿蒙金融理财全栈项目:生态合作与用户运营优化
  • Linux Socket 编程:UDP 套接字通信实战
  • Git 连接 GitHub 失败解决方案:代理与网络配置排查
  • 私有化大模型在十类企业场景中的应用与效能分析
  • AMD 显卡在 Windows WSL 环境中部署 Stable Diffusion WebUI 及 ComfyUI
  • 鸿蒙金融理财全栈项目:合规审计、风险控制与产品创新优化
  • everything-claude-code 开源配置方案与使用指南
  • 网络安全人士必备的 30 个安全工具
  • 免费 Trae 编辑器实测:排队机制与工程效率的权衡
  • Dify MCP-Server 插件将工作流发布为第三方可调用服务
  • Python 实现定时任务的八种常见方案
  • OpenClaw 腾讯云服务器部署与飞书对接实战
  • C++ STL list 容器底层实现分析
  • C++ STL 容器详解:unordered_map 与 unordered_set 实战指南
  • AI 应用架构师指南:智能 Web3 开发框架核心要点
  • MySQL 8.0.x 跨平台安装实战:Windows、CentOS、Ubuntu 配置详解
  • 企业级 Agent 构建实战:从 RAG 到自主智能体的全栈架构
  • faster-whisper 语音转文字工具使用指南

相关免费在线工具

  • 加密/解密文本

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

  • 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

  • Gemini 图片去水印

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