本次主要通过前缀和,来优化算法的时间复杂度,将O(n)的时间复杂度优化为O(1)常数级
前言
本次主要通过前缀和,来优化算法的时间复杂度,将O(n)的时间复杂度优化为O(1)常数级。
一、前缀和是什么?
1.引入一位数组arr
通常我们引入一个一维数组arr,例如此时我们引入的数组arr。
int[] arr = {0,a1,a2,a3,a4,a5};
2.创建前缀和数组pre
我们可以再创建一个前缀和数组,即第一个元素表示a1,第二个元素表示a1+a2,后续的依次类推
int[] pre = new int[arr.length];
for(int i = 1;i < arr.length;i++{
per[i] = per[i-1] + arr[i];
}
此时我们的前缀和数组pre就变为{0,a1,a1+a2,a1+a2+a3,a1+a2+a3+a4,a1+a2+a3+a4+a5}.
3.前缀和的算法思想
例如如果我们要求a3到a5元素的和以往是通过一个循环,设置一个res变量,然后从a3遍历a5,累加就可以得到结果。但是我们通过观察前缀和数组pre可以发现,我们如果要求a3+a4+a5,我们只需要用pre[5]-pre[2]即可求出结果,这样我们就可将求前缀和的时间复杂度从O(n)将为O(1)。(注:数组下标从0开始)
4.结论
从上述计算我们可以得知,如果我们要求某个区间的元素和,例如求从l-r,我们就可以通过先构建前缀和数组,然后通过公式result = pre[r]-pre[l-1]就可以直接得到结果。(注:我们通过在数组中多添加了一个起始元素0,这样可以避免我们用前缀和数组进行从第1个元素到第2个元素的前缀和采用公式而出现数组下标越界的问题,而且第一个元素直接就是p[1]。)
。二、使用步骤
1.代码如下(示例):
import java.io.*;
public class 前缀和 {
static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
public static void main(String[] args) throws Exception{
int n = nextInt();
int m = nextInt();
int[] arr = new int[n+1];
int[] s = new int[n+1];
//录入arr数组数据
for (int i = 1; i < arr.length; i++) {
arr[i] = nextInt();
}
//构建前缀和数组
for(int i = 1;i <= n;i++){
s[i] = s[i-1] + arr[i];
}
while (m-- > 0){
//录入区间起始位置
int l = nextInt() ;
//录入区间末尾位置
int r = nextInt();
//求区间和公式
int result = s[r] - s[l-1];
pw.println(result);
}
pw.flush();
}
public static int nextInt()throws Exception{
st.nextToken();
return (int)st.nval;
}
}
2.读入数据
测试样例数据如下(示例):
5 3
2 1 3 6 4
1 2
1 3
2 4
代码运行结果如下
3
6
10
测试数据解释:
3 = 2 + 1
6 = 2 + 1 +3
10 = 1 + 3 + 6
总结
一维数组的前缀和我们主要可以以此来解决区间求和问题,同时我们也可以通过一维数组前缀和来推广到二维数组求区间和的问题,下次更新二维数组的区间和。