leetcode周赛遇到的hard题,题目在最后,当时做的时候毫无头绪,因为本人差分做的也很少,所有完全没往差分上面想,然后就开始坐牢。所以总结一下前缀和以及差分数组的知识点。
假设现在有个需求,给想知道指定一维数组某个区间的和,怎么求?
例如数组[1,2,3,4,5,4,3,2,3],数组长度为n,我想知道下标2到5区间内数组元素的和,最直观的做法如下
public int demo(int[] nums, int l, int r) {
int sum = 0;
for (int i = l; i <= r; i++) {
sum += nums[i];
}
return sum;
}
复制代码
很显然,没有比这更优的解法了,时间复杂度O(n),空间复杂度O(1)
1、假设我不仅需要求区间[2,5]的和,我还需要求[1,3]、[4,5]...的和,即我会给m个[l,r],但是数组nums是固定的,同样的,依然可以用上述方法解决,你每次都调用demo方法就可以了,但是这样的时间复杂度是O(n*m)了,很容易超时。
2、对于这种情况我们可以用到前缀和的思想,构造一维数组的前缀和
原来的数组 nums [1,2,3,4,5,4,3,2,3]
前缀和数组 sum [1,3,6,10,15,19,22,24,27]
复制代码
构造代码如下
for (int i = 1; i < nums.length; i++) {
nums[i] += nums[i - 1];
}
复制代码
3、现在有了前缀和数组,我们该怎么求区间[l,r]的范围和呢?
不难想到,求区间[l,r]的和,就是求(1+2+3+...+r)-(1+2+3+...+l-1)的和
怎么理解,比如我有个数组是[0,1,2,3,4,5,6,7,8,9,10],我要求[2,4]的和,可以先求[0,4]的和,就是0+1+2+3+4,再求[0,1]的和,就是0+1,那么0+1+2+3+4是不是比0+1多了2+3+4,是不是正好就是区间[2,4]的和?
通解就是sum[l,r] = sum[r] - sum[l - 1] (这里l-1会越界,读者可以特判,或者让数组的长度为n+1)
类似一维前缀和,如果多次求区间内范围和,就可以用到二维前缀和的思想,那么二维数组的区间是什么? 假设红色矩阵左上角的坐标是[i,j],右下角的坐标是[m,n],用这两个坐标是不是可以圈出这个矩阵了
那现在我这个红色矩阵的和是不是很好求了,直接遍历就可以了
public int demo(int[][] matrix, int i, int j, int m, int n) {
int sum = 0;
for (int k = i; k <= m; k++) {
for (int l = j; l <= n; l++) {
sum += matrix[k][l];
}
}
return sum;
}
复制代码
如果我想求多次呢?那每一次都像上面的解法就很慢了,有没有一行代码就能求出来的解