前缀和与差分(一维、二维)


什么是前缀和?前缀和就是一个数组的某项下标之前(包括此项元素)的所有数组中的元素的和。

一维前缀和与差分

s u m sum sum为前缀和数组, a r r arr arr为原数组,那么就存在:
s u m [ i ] = a r r [ 0 ] + a r r [ 1 ] + . . . + a r r [ i ] sum[i]=arr[0]+arr[1]+...+arr[i] sum[i]=arr[0]+arr[1]+...+arr[i]
可以得到如下递推式
s u m [ i ] = s u m [ i − 1 ] + a r r [ i ] sum[i]=sum[i-1]+arr[i] sum[i]=sum[i1]+arr[i]
可以得到
a r r [ j ] + a r r [ j + 1 ] + . . . + a r r [ i ] = s u m [ i ] − s u m [ j − 1 ] arr[j]+arr[j+1]+...+arr[i]=sum[i]-sum[j-1] arr[j]+arr[j+1]+...+arr[i]=sum[i]sum[j1]

题目一:leetcode 560. 和为 K 的子数组

题目地址

给你一个整数数组 n u m s nums nums 和一个整数 k k k ,请你统计并返回该数组中和为 k k k 的连续子数组的个数。

示例 1

输入:nums = [1,1,1], k = 2
输出:2

示例 2

输入:nums = [1,2,3], k = 3
输出:2

提示

1 <= n u m s . l e n g t h nums.length nums.length <= 2 ∗ 1 0 4 2 * 10^4 2104
-1000 <= n u m s [ i ] nums[i] nums[i] <= 1000
− 1 0 7 -10^7 107 <= k k k<= 1 0 7 10^7 107

代码

import java.util.HashMap;
class Solution {
    public int subarraySum(int[] nums, int k) {
    	//return method1(nums,k); //0(n^2)
        return method2(nums,k);//0(n)
    }
    /*
    利用前缀和,时间复杂度0(n^2)
    */
    public int method1(int[] nums,int k){
        int res=0;
        for(int i=0;i<nums.length;i++){
            int cur=0;
            for(int j=i;j<nums.length;j++){
                cur+=nums[j];
                if(cur==k) res++;
            }
        }
        return res;
    }
    /*
    利用前缀和 + Map优化 时间复杂度0(n)
    前缀和数组sum[i]=arr[0]+arr[1]+...+arr[i]
    若arr[j]+arr[j+1]+...+arr[i]=k,则有sum[i]-sum[j-1]=k
    也就是说,对于sum[i],如果存在sum[j-1]=sum[i]-k,那么就可以求出j,
    从而可以得到该子数组
    设置map<sum,number>,sum:前缀和,number:前缀和为sum的前缀和数组个数
    */
    public int method2(int[] nums,int k){
        HashMap<Integer,Integer> map=new HashMap<>();
        map.put(0,1);
        int n=nums.length;
        int[] sum=new int[n];
        sum[0]=nums[0];
        for(int i=1;i<n;i++){
            sum[i]=sum[i-1]+nums[i];
        }
        int res=0;
        for(int i=0;i<n;i++){
            if(map.containsKey(sum[i]-k)){
                res+=map.get(sum[i]-k);
            }
            if(map.containsKey(sum[i])){
                map.put(sum[i],map.get(sum[i])+1);
            }else{
                map.put(sum[i],1);
            }
        }
        return res;
    }
}

二维前缀和与差分

s u m sum sum为前缀和数组, a r r arr arr为原数组,那么就存在:

s u m [ x ] [ y ] sum[x][y] sum[x][y]= ∑ i = 0 x \displaystyle\sum_{i=0}^{x} i=0x ∑ j = 0 y a r r [ i ] [ j ] \displaystyle\sum_{j=0}^{y} arr[i][j] j=0yarr[i][j]

根据下面的图片,可以得到如下递推式

s u m [ x ] [ y ] = s u m [ x − 1 ] [ y ] + s u m [ x ] [ y − 1 ] − s u m [ x − 1 ] [ y − 1 ] + a r r [ x ] [ y ] sum[x][y]=sum[x-1][y]+sum[x][y-1]-sum[x-1][y-1]+arr[x][y] sum[x][y]=sum[x1][y]+sum[x][y1]sum[x1][y1]+arr[x][y]

可以得到

∑ i = x 1 x 2 \displaystyle\sum_{i=x1}^{x2} i=x1x2 ∑ j = y 1 y 2 a r r [ i ] [ j ] \displaystyle\sum_{j=y1}^{y2} arr[i][j] j=y1y2arr[i][j] = s u m [ x 2 ] [ y 2 ] − s u m [ x 1 − 1 ] [ y 2 ] − s u m [ x 2 ] [ y 1 − 1 ] + s u m [ x 1 − 1 ] [ y 1 − 1 ] sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1] sum[x2][y2]sum[x11][y2]sum[x2][y11]+sum[x11][y11]
在这里插入图片描述
如上图所示, s u m [ x ] [ y ] = 红 色 区 域 的 值 + 黄 色 区 域 的 值 + 蓝 色 区 域 的 值 + 绿 色 区 域 的 值 sum[x][y]=红色区域的值+黄色区域的值+蓝色区域的值+绿色区域的值 sum[x][y]=+++绿

各区域的值分别如下:

蓝 色 区 域 的 值 = s u m [ x − 1 ] [ y ] − s u m [ x − 1 ] [ y − 1 ] 蓝色区域的值=sum[x-1][y]-sum[x-1][y-1] =sum[x1][y]sum[x1][y1]
黄 色 区 域 的 值 = s u m [ x ] [ y − 1 ] − s u m [ x − 1 ] [ y − 1 ] 黄色区域的值=sum[x][y-1]-sum[x-1][y-1] =sum[x][y1]sum[x1][y1]
红 色 区 域 的 值 = s u m [ x − 1 ] [ y − 1 ] 红色区域的值=sum[x-1][y-1] =sum[x1][y1]
绿 色 区 域 的 值 = a r r [ x ] [ y ] 绿色区域的值=arr[x][y] 绿=arr[x][y]

综上所述,可以得到:

s u m [ x ] [ y ] = s u m [ x − 1 ] [ y ] + s u m [ x ] [ y − 1 ] − s u m [ x − 1 ] [ y − 1 ] + a r r [ x ] [ y ] sum[x][y]=sum[x-1][y]+sum[x][y-1]-sum[x-1][y-1]+arr[x][y] sum[x][y]=sum[x1][y]+sum[x][y1]sum[x1][y1]+arr[x][y]
在这里插入图片描述
如上图所示

∑ i = x 1 x 2 \displaystyle\sum_{i=x1}^{x2} i=x1x2 ∑ j = y 1 y 2 a r r [ i ] [ j ] \displaystyle\sum_{j=y1}^{y2} arr[i][j] j=y1y2arr[i][j] = 绿 色 区 域 的 值 绿色区域的值 绿
s u m [ x 2 ] [ y 2 ] = 绿 色 + 黄 色 + 红 色 + 蓝 色 区 域 的 值 sum[x2][y2]=绿色+黄色+红色+蓝色区域的值 sum[x2][y2]=绿+++
s u m [ x 1 − 1 ] [ y 2 ] = 红 色 + 蓝 色 区 域 的 值 sum[x1-1][y2]=红色+蓝色区域的值 sum[x11][y2]=+
s u m [ x 2 ] [ y 1 − 1 ] = 红 色 + 黄 色 区 域 的 值 sum[x2][y1-1]=红色+黄色区域的值 sum[x2][y11]=+
s u m [ x 1 − 1 ] [ y 1 − 1 ] = 红 色 区 域 的 值 sum[x1-1][y1-1]=红色区域的值 sum[x11][y11]=
绿 色 区 域 的 值 = s u m [ x 2 ] [ y 2 ] − s u m [ x 1 − 1 ] [ y 2 ] − s u m [ x 2 ] [ y 1 − 1 ] + s u m [ x 1 − 1 ] [ y 1 − 1 ] 绿色区域的值=sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1] 绿=sum[x2][y2]sum[x11][y2]sum[x2][y11]+sum[x11][y11]

那么就可以得到

∑ i = x 1 x 2 \displaystyle\sum_{i=x1}^{x2} i=x1x2 ∑ j = y 1 y 2 a r r [ i ] [ j ] \displaystyle\sum_{j=y1}^{y2} arr[i][j] j=y1y2arr[i][j] = s u m [ x 2 ] [ y 2 ] − s u m [ x 1 − 1 ] [ y 2 ] − s u m [ x 2 ] [ y 1 − 1 ] + s u m [ x 1 − 1 ] [ y 1 − 1 ] sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1] sum[x2][y2]sum[x11][y2]sum[x2][y11]+sum[x11][y11]

相关习题

牛妹吃豆子

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值