您的位置:首页 >如何在 Java 中利用数组实现简单的前缀和(Prefix Sum)技术以支持 O(1) 时间的区间查询
发布于2026-05-03 阅读(0)
扫一扫,手机访问

在 Ja va 开发中,尤其是处理数据查询时,你是否遇到过这样的场景:需要频繁计算一个数组中某个连续区间的元素之和?如果每次都去遍历累加,效率显然不高。这时候,前缀和(Prefix Sum)技术就该登场了。它的核心思路非常巧妙:通过一次性的预处理,将后续所有区间求和的复杂度降至 O(1)。
具体怎么实现呢?关键在于构建一个辅助数组。假设我们有一个原始数组 nums,长度为 n。通常,我们会选择构建一个长度为 n + 1 的“带哨兵”前缀和数组 prefix。这个小小的“+1”设计,能让我们在后续计算时省去不少边界判断的麻烦。
prefix[0] = 0。i = 1 开始遍历到 n,执行 prefix[i] = prefix[i - 1] + nums[i - 1]。这样一来,prefix[i] 存储的值,就恰好是原数组 nums 中从第 0 个元素到第 i-1 个元素的总和。整个预处理过程只需要 O(n) 的时间。
预处理完成后,真正的魔法就发生了。当我们需要查询原数组中任意闭区间 [left, right](其中 0 ≤ left ≤ right < n)的和时,只需要一个简单的减法:
sum = prefix[right + 1] - prefix[left]
这个公式为什么成立?我们拆解一下:
prefix[right + 1] 代表了 nums[0] 到 nums[right] 的所有元素之和。prefix[left] 代表了 nums[0] 到 nums[left - 1] 的所有元素之和。nums[left] 到 nums[right] 的区间和。看,一次查询,无论区间多长,都只需要常数时间,效率的提升立竿见影。
理论说清楚了,来看一个完整、可直接运行的 Ja va 示例代码,它会让你理解得更透彻:
public class PrefixSum { private int[] prefix;public PrefixSum(int[] nums) { int n = nums.length; prefix = new int[n + 1]; for (int i = 1; i <= n; i++) { prefix[i] = prefix[i - 1] + nums[i - 1]; } } // 查询 [left, right] 闭区间的和,O(1) public int rangeSum(int left, int right) { return prefix[right + 1] - prefix[left]; } // 使用示例 public static void main(String[] args) { int[] nums = {2, 1, 3, 5, 4}; PrefixSum ps = new PrefixSum(nums); System.out.println(ps.rangeSum(1, 3)); // nums[1]+nums[2]+nums[3] = 1+3+5 = 9 System.out.println(ps.rangeSum(0, 4)); // 全数组和 = 15 }}
注意事项与扩展
当然,前缀和技术并非万能钥匙。它最适合处理“静态数组”,也就是那些初始化后就不太会频繁修改元素值的场景。如果业务需求中需要支持大量的单点更新操作,那么前缀和每次更新都需要重新计算一大片,效率就不够看了。这时候,就该考虑更高级的数据结构,比如线段树或者树状数组(Fenwick Tree)。
最后,再划几个重点:
- 复杂度:空间复杂度为 O(n),预处理时间复杂度为 O(n),查询则是 O(1)。
- 边界检查:在实际生产代码中,务必记得在查询方法中加入索引越界的校验,例如判断
left和right是否在合法范围内,以及left是否小于等于right。- 思路延伸:这个一维前缀和的思路完全可以推广到二维,也就是“二维前缀和”,用于高效计算一个矩阵中任意子矩阵内所有元素的和,这在图像处理、动态规划等算法中非常有用。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
9