一维前缀和问题

问题描述

今天在牛客上刷算法题时,碰到这样一道题,题目要求我们用前缀和解题,但是我并没有太深入了解过这个算法,于是只能暴力求解,但是发现提交后都显示超时或有些案例不通过,我百思不得其解,于是通过网上的搜索和看题解的方法终于对前缀和问题有了清晰的认识。
题目如下:
在这里插入图片描述

解法对比

方法一:暴力解法

最直观的想法就是每次查询都遍历区间 [l, r],累加所有元素。

import java.util.Scanner;

public class ForceDemo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int q = sc.nextInt();
        
        int[] arr = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            arr[i] = sc.nextInt();
        }

        for (int i = 0; i < q; i++) {
            int l = sc.nextInt();
            int r = sc.nextInt();
            
            // 暴力计算区间和
            long sum = 0;
            for (int j = l; j <= r; j++) {
                sum += arr[j];
            }
            
            System.out.println(sum);
        }
        
        sc.close();
    }
}

时间复杂度: O(m × n),最坏情况下每次查询都要遍历整个数组
空间复杂度: O(n)

方法二:前缀和优化

前缀和的核心思想是预处理,用空间换时间。我们先计算出前缀和数组,然后利用公式快速计算区间和。

关键公式: sum[l, r] = prefixSum[r] - prefixSum[l-1]

import java.util.Scanner;

public class PrefixSum {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int q = sc.nextInt();
        
        int[] arr = new int[n + 1]; 
        long[] prefixSum = new long[n + 1]; 
        
        // 读入数组并构建前缀和
        for (int i = 1; i <= n; i++) {
            arr[i] = sc.nextInt();
            prefixSum[i] = prefixSum[i - 1] + arr[i];
        }
        
        // 处理查询
        for (int i = 0; i < q; i++) {
            int l = sc.nextInt();
            int r = sc.nextInt();
            
            // O(1)计算区间和
            long sum = prefixSum[r] - prefixSum[l - 1];
            System.out.println(sum);
        }
        
        sc.close();
    }
}

时间复杂度: O(n + m),预处理O(n),每次查询O(1)
空间复杂度: O(n)

算法原理详解

前缀和的构建过程

假设原数组为:[3, 5, 2, 7, 1]
前缀和数组的构建:

prefixSum[0] = 0         
prefixSum[1] = 0 + 3 = 3
prefixSum[2] = 3 + 5 = 8  
prefixSum[3] = 8 + 2 = 10
prefixSum[4] = 10 + 7 = 17
prefixSum[5] = 17 + 1 = 18

区间和计算

要计算区间 [2, 4] 的和:

sum[2,4] = prefixSum[4] - prefixSum[1] = 17 - 3 = 14

prefixSum[4] 表示前4个元素的和:3+5+2+7= 17,而prefixSum[1] 表示前1个元素的和:3
最后两者相减得到第2到第4个元素的和为14。

性能分析

解法预处理时间单次查询时间总时间复杂度
暴力解法O(1)O(n)O(m × n)
前缀和O(n)O(1)O(n + m)

如果 n = 10⁶, q = 10⁶,暴力解法:最多需要 10¹² 次操作,而前缀和:只需要 2 × 10⁶ 次操作。
于是我们可以得出一个结论: 当查询次数较多时,前缀和算法能将时间复杂度从 O(m × n) 优化到 O(n + m),效率非常高。

总结

前缀和的核心作用是快速计算任意区间的元素和

  • 通过预处理构建前缀和数组
  • 利用公式 sum[l,r] = prefixSum[r] - prefixSum[l-1] 在 O(1) 时间内计算区间和
  • 将多次区间查询的时间复杂度从 O(m×n) 优化到 O(n+m)

以上属个人总结,欢迎各位学者评论指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值