算法学习:前缀和

文章目录

  • 一、前缀和的用途
  • 二、算法运用
    • 1.一维数组计算和
    • 2.二维矩阵计算和
    • 3.统计子数组数量
  • 总结


一、前缀和的用途

        运用前缀和的思想,可以在索引区间内更有效率地求出元素和。使用前缀和可以有效地避免for循环反复调用从而减少sumrange方法的调用频率,降低sumrange的时间复杂度,提高整个程序的运行效率。

二、算法运用

1.一维数组计算和

        下面选用力扣的303. 区域和检索 - 数组不可变练习,详情请读者自动跳转至原题。

        该题解题思路在于先算出各个连续的元素和,用减法去算区间内的和,相比一个个数相加,其时间复杂度降为O(1),提高了算法效率。

        以下为图解:

代码如下(示例):

class NumArray {
    private int[] presum;//构建数组
    public NumArray(int[] nums) {
        presum=new int[nums.length+1];
        for(int i=1;i<presum.length;i++)
        {
            presum[i]=presum[i-1]+nums[i-1];//计算数组累加和
        }
    }
    //查询目标区间内的和
    public int sumRange(int left, int right) {
        return presum[right+1]-presum[left];
    }
}

2.二维矩阵计算和

        下面选用力扣的304. 二维区域和检索 - 矩阵不可变练习,详情请读者自动跳转至原题。

         该题的解题思路在于先计算出所有类型矩阵的元素和,再找到合适的大矩阵去加减小矩阵算出目标值,矩阵内的元素和计算没有难度,关键在于找到一个共同的顶点,便于各个矩阵的计算。

        以下为图解:

代码如下(示例):

class NumMatrix {
    private int[][] presum;//存储各矩阵元素和
    public NumMatrix(int[][] matrix) {
        int m=matrix.length,n=matrix[0].length;
        if(m==0||n==0) return;
        presum =new int[m+1][n+1];//构造前缀和矩阵
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
            presum[i][j]=presum[i-1][j] +presum[i][j-1]+matrix[i-1][j-1]-presum[i-1][j-1];//计算[0,0]~[i,j]各矩阵元素和
            }
        }
    }
    //计算目标矩阵元素之和
    public int sumRegion(int row1, int col1, int row2, int col2) {
        return presum[row2+1][col2+1]-presum[row1][col2+1]-presum[row2+1][col1]+presum[row1][col1];
    }
}

3.统计子数组数量

         下面选用力扣的560. 和为 K 的子数组练习,详情请读者自动跳转至原题。

        该题解题思路类似于一维数组,其不同点在于在前缀和中找与K互补的值,也运用到哈希表去映射前缀和出现的次数,提高算法效率。

        以下为图解:

代码如下(示例):

class Solution {
    public int subarraySum(int[] nums, int k) {
        int n=nums.length;
        int[] presum=new int[n+1];//存储前缀和
        HashMap<Integer,Integer> count =new HashMap<>();//当前前缀和出现次数的映射
        count.put(0,1);//记录下标为0的第一个前缀和0出现1次
        int m=0;//记录和为k的子数组数量
        for(int i=1;i<=n;i++){
            presum[i]=presum[i-1]+nums[i-1];//计算前缀和
            int target=presum[i]-k;//逆向思维寻找条件值
            if(count.containsKey(target)){//查询目标值是否在哈希表中
                m+=1;
            }
            //将当前前缀和存入哈希表
            if(!count.containsKey(presum[i])){
                count.put(presum[i],1);//记录该数第一次出现
            }
            else count.put(presum[i],count.get(presum[i])+1);//记录该数多次出现
        }
        return m;
    }
}

总结

        一维数组:先算各区间的和,利用区间和算出目标值

        二维数组:找到一个共同的顶点(从目标矩阵的四个顶点中找到最合适的一个),以顶点向四周矩形状发散,通过大矩形加减内部小矩形的方式算出目标区域的元素和

        子数组的数量查找:类似于一维数组先进行前缀和的存储,然后根据题意利用已算好的前缀和去找到目标值,其难点在于利用哈希表去存储前缀和并映射出其出现的次数,方便查找

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值