《leetcode》寒假刷前缀和《前缀和》

303. 区域和检索 - 数组不可变

难度简单236

给定一个整数数组  nums,求出数组从索引 i 到 ji ≤ j)范围内元素的总和,包含 i两点。

实现 NumArray 类:

  • NumArray(int[] nums) 使用数组 nums 初始化对象
  • int sumRange(int i, int j) 返回数组 nums 从索引 i 到 ji ≤ j)范围内元素的总和,包含 i两点(也就是 sum(nums[i], nums[i + 1], ... , nums[j])

 

示例:

输入:
["NumArray", "sumRange", "sumRange", "sumRange"]
[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]
输出:
[null, 1, -1, -3]

解释:
NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]);
numArray.sumRange(0, 2); // return 1 ((-2) + 0 + 3)
numArray.sumRange(2, 5); // return -1 (3 + (-5) + 2 + (-1)) 
numArray.sumRange(0, 5); // return -3 ((-2) + 0 + 3 + (-5) + 2 + (-1))

 

提示:

  • 0 <= nums.length <= 104
  • -105 <= nums[i] <= 105
  • 0 <= i <= j < nums.length
  • 最多调用 104 次 sumRange 方法

Code:时间复杂度:O(n) 查询时间复杂度:O(1) 空间复杂度:O(n)

class NumArray {
    private int Nums[]; 
    private int sum[];
    //前缀和
    public NumArray(int[] nums) {
        //Nums=Arrays.copyOf(nums,nums.length);//Arrays.Copyof()拷贝数组,其内部调用了System.arrayCopy()方法,从下标0开始,如果超过原数组长度,会用null进行填充。     
        sum=new int[nums.length];
        if(nums.length>=1) sum[0]=nums[0];
        for(int i=1;i<nums.length;i++)//sum[i] 从0到i的和  求 i j 和 sum相减即可
            sum[i]+=sum[i-1]+nums[i];
    }
    
    public int sumRange(int i, int j) {
        return i==0?sum[j]:sum[j]-sum[i-1];
    }
}

/**
 * Your NumArray object will be instantiated and called as such:
 * NumArray obj = new NumArray(nums);
 * int param_1 = obj.sumRange(i,j);
 */

304. 二维区域和检索 - 矩阵不可变

难度中等144

给定一个二维矩阵,计算其子矩形范围内元素的总和,该子矩阵的左上角为 (row1, col1) ,右下角为 (row2, col2)。

Range Sum Query 2D
上图子矩阵左上角 (row1, col1) = (2, 1) ,右下角(row2, col2) = (4, 3),该子矩形内元素的总和为 8。

示例:

给定 matrix = [
  [3, 0, 1, 4, 2],
  [5, 6, 3, 2, 1],
  [1, 2, 0, 1, 5],
  [4, 1, 0, 1, 7],
  [1, 0, 3, 0, 5]
]

sumRegion(2, 1, 4, 3) -> 8
sumRegion(1, 1, 2, 2) -> 11
sumRegion(1, 2, 2, 4) -> 12

说明:

  1. 你可以假设矩阵不可变。
  2. 会多次调用 sumRegion 方法
  3. 你可以假设 row1 ≤ row2 且 col1 ≤ col2。

通过次数15,601提交次数33,021

Code: 时间复杂度:O(mn) 查询时间复杂度:O(1) 空间复杂度:O(mn)

class NumMatrix {
    //前缀和l
    private int dp[][];
    public NumMatrix(int[][] matrix) {
        if(matrix.length==0||matrix[0].length==0) return;
         //初始化 从 (1,1)开始算 0行0列都是0 为了减少判断
        dp=new int[matrix.length+1][matrix[0].length+1];
       
        for(int i=0;i<matrix.length;i++)
        {
            for(int j=0;j<matrix[0].length;j++)
            {
                //正常情况下,应该是matrix[i+1][j+1] 但是实际上题目给的题意是从0开始,但是我们是从1开始的,所以我们的matrix[1][1]对应题意的matrix[0][0];
                dp[i+1][j+1]=dp[i+1][j]+dp[i][j+1]+matrix[i][j]-dp[i][j];
            }
        }
    }
    
    public int sumRegion(int row1, int col1, int row2, int col2) {
        //我们从1开始
        return dp[row2+1][col2+1]-dp[row2+1][col1]-dp[row1][col2+1]+dp[row1][col1];
    }
}

/**
 * Your NumMatrix object will be instantiated and called as such:
 * NumMatrix obj = new NumMatrix(matrix);
 * int param_1 = obj.sumRegion(row1,col1,row2,col2);
 */

 

560. 和为K的子数组

难度中等774

给定一个整数数组和一个整数 k,你需要找到该数组中和为 的连续的子数组的个数。

示例 1 :

输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。

说明 :

  1. 数组的长度为 [1, 20,000]。
  2. 数组中元素的范围是 [-1000, 1000] ,且整数 的范围是 [-1e7, 1e7]。

Code:时间复杂度:O(n)  空间复杂度:O(n)

class Solution {
    public int subarraySum(int[] nums, int k) {
        if(nums.length==0) return 0;
        
        int ans=0;
        //使用前缀和,只关心数量,不关心是哪一个,所以可以直接统计数量,用hashMap
        HashMap<Integer,Integer>preMap=new HashMap<Integer,Integer>();
        int preSum=0;
        //初始化,模拟所有sum[i]-sum[j]中,sum[j]=0的情况,即没有前缀的情况。
        preMap.put(0,1);

        for(int i=0;i<nums.length;i++)
        {
            preSum+=nums[i];
            //System.out.println(preSum+" "+ans);
            if(preMap.containsKey(preSum-k))
                ans+=preMap.get(preSum-k);//如果可以找到这样的前缀,就可以确定有一定数量的(数量存在map中)连续序列之和为k。
            preMap.put(preSum,preMap.getOrDefault(preSum,0)+1);
        }
       
        return ans;
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值