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

前缀和算法实战:连续数组与矩阵区域和

基于前缀和思想解决两类典型问题。对于连续数组,将 0 视为 -1 转化为寻找和为 0 的子数组,利用哈希表记录前缀和首次出现位置实现 O(n) 求解。对于矩阵区域和,构建二维前缀和数组,通过坐标映射快速计算任意矩形区域的元素总和,避免重复遍历。代码提供 C++ 与 Java 实现,重点讲解边界处理与状态转移逻辑。

魔尊发布于 2026/3/16更新于 2026/6/2625 浏览
前缀和算法实战:连续数组与矩阵区域和

前缀和算法实战:连续数组与矩阵区域和

031 连续数组

题目链接: 525. 连续数组

问题描述

给定一个二进制数组 nums,找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。

文章配图

解题思路

暴力枚举所有子数组的时间复杂度为 O(n²),在数据量较大时容易超时。我们可以利用前缀和结合哈希表将时间复杂度优化至 O(n)。

核心转化思想如下:

  1. 如果将数组中的 0 记为 -1,1 记为 1,那么问题就转化为寻找一段区间,其元素之和等于 0。
  2. 设 sum[i] 表示从索引 0 到 i 的前缀和。若存在两个位置 i 和 j(假设 i < j),使得 sum[j] - sum[i] = 0,即 sum[j] == sum[i],则说明区间 [i+1, j] 内的元素和为 0。
  3. 为了得到最长子数组,我们需要记录每个前缀和第一次出现的位置。当再次遇到相同的前缀和时,用当前位置减去首次出现的位置即可得到长度。

代码实现

C++ 实现
class Solution {
public:
    int findMaxLength(vector<int>& nums) {
        unordered_map<int, int> hash;
        // 初始化前缀和为 0 的位置为 -1,处理从索引 0 开始的子数组
        hash[0] = -1;
        
        int sum = 0;
        int ret = 0;
        
        for (int i = 0; i < nums.size(); ++i) {
            // 0 视为 -1,1 视为 1
            sum += (nums[i] == 0 ? -1 : 1);
            
            if (hash.count(sum)) {
                // 如果之前出现过相同的前缀和,更新最大长度
                ret = max(ret, i - hash[sum]);
            } else {
                // 仅记录第一次出现的位置
                hash[sum] = i;
            }
        }
        return ret;
    }
};
Java 实现
class Solution {
    public int findMaxLength(int[] nums) {
        Map<Integer, Integer> hash = new HashMap<>();
        // 默认存在一个前缀和为 0 的情况,对应索引 -1
        hash.put(0, -1);
        
        int sum = 0;
        int 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),其中 n 是数组长度。我们只需遍历一次数组。
  • 空间复杂度: O(n),哈希表在最坏情况下需要存储 n 个不同的前缀和。

032 矩阵区域和

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

问题描述

给你一个 m x n 的矩阵 mat 和一个整数 k,请你返回一个矩阵 answer,其中每个 answer[i][j] 是所有满足以下条件的元素 mat[r][c] 的和:

  • i - k <= r <= i + k
  • j - k <= c <= j + k
  • (r, c) 在矩阵内

解题思路

这是一个典型的二维前缀和应用题。直接计算每个点的区域和会导致重复计算,时间复杂度较高。通过预处理构建二维前缀和数组,可以在 O(1) 时间内计算出任意矩形区域的和。

关键步骤在于确定目标矩形的左上角和右下角坐标,并进行边界检查:

  1. 左上角坐标: x1 = max(0, i - k), y1 = max(0, j - k)
  2. 右下角坐标: x2 = min(m - 1, i + k), y2 = min(n - 1, j + k)

注意:由于前缀和数组通常多开一行一列以简化边界处理,实际查询时需进行下标映射调整。

代码实现

C++ 实现
class Solution {
public:
    vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {
        int m = mat.size(), n = mat[0].size();
        // 创建 (m+1) x (n+1) 的前缀和数组,dp[i][j] 表示左上角 (0,0) 到 (i-1,j-1) 的和
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
        
        // 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) {
                // 确定查询区域的边界,注意 dp 数组下标偏移 +1
                int x1 = max(0, i - k) + 1;
                int y1 = max(0, j - k) + 1;
                int x2 = min(m - 1, i + k) + 1;
                int 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;
    }
};
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;
                int y1 = Math.max(0, j - k) + 1;
                int x2 = Math.min(m - 1, i + k) + 1;
                int 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(m * n),其中 m 和 n 分别为矩阵的行数和列数。我们需要遍历整个矩阵两次(一次构建前缀和,一次生成结果)。
  • 空间复杂度: O(m * n),用于存储二维前缀和数组。

总结

这两道题展示了前缀和在不同维度下的应用技巧。一维场景下配合哈希表可以解决子数组求和问题,而二维场景下则需要构建二维前缀和矩阵来快速响应区域查询。掌握这种'预处理 + 公式计算'的模式,能显著提升处理范围统计类问题的效率。

目录

  1. 前缀和算法实战:连续数组与矩阵区域和
  2. 031 连续数组
  3. 问题描述
  4. 解题思路
  5. 代码实现
  6. C++ 实现
  7. Java 实现
  8. 复杂度分析
  9. 032 矩阵区域和
  10. 问题描述
  11. 解题思路
  12. 代码实现
  13. C++ 实现
  14. Java 实现
  15. 复杂度分析
  16. 总结
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • AI 驱动数据库操作:核心场景与实战指南
  • faster-whisper 语音识别实战:从安装到性能调优
  • Qwen3-TTS-Tokenizer-12Hz在AR眼镜实时语音交互中的低延迟应用
  • npm 安装 OpenClaw 遇到 Git 报错的解决方案
  • 从零搭建 SpringBoot 项目详解
  • MoltBot 集成钉钉 Stream 流式接入配置指南
  • Qwen-Image-Edit-2511-Multiple-Angles LoRA 多角度 AI 图像生成指南
  • OpenClaw Gateway 服务运维指南:启动、停止与监控
  • Java 异常处理:从原理到实战最佳实践
  • Qwen3.5 系列开源大模型本地部署全流程
  • 城市花园小区维修管理系统的设计与实现
  • Java CountDownLatch 原理、应用与最佳实践
  • 网络通讯核心协议详解:TCP、UDP、HTTP 与 HTTPS
  • LeetCode 141:环形链表判断的两种经典解法
  • Linux 网络编程实战:TCP/IP 协议栈与 UDP 通信
  • Python 中 GraphQL 的实现与实战指南
  • Python 数据统计指南:从环境配置到高级分析
  • Ubuntu 实体机与虚拟机安装及配置避坑指南
  • FPGA 中 RS485 收发器应用与毛刺处理方案
  • SpringBoot 集成 MinIO 文件服务器配置与使用

相关免费在线工具

  • 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