303. 区域和检索 - 数组不可变
难度简单236
给定一个整数数组 nums
,求出数组从索引 i
到 j
(i ≤ j
)范围内元素的总和,包含 i
、j
两点。
实现 NumArray
类:
NumArray(int[] nums)
使用数组nums
初始化对象int sumRange(int i, int j)
返回数组nums
从索引i
到j
(i ≤ j
)范围内元素的总和,包含i
、j
两点(也就是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)。
上图子矩阵左上角 (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
说明:
- 你可以假设矩阵不可变。
- 会多次调用 sumRegion 方法。
- 你可以假设 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,你需要找到该数组中和为 k 的连续的子数组的个数。
示例 1 :
输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
说明 :
- 数组的长度为 [1, 20,000]。
- 数组中元素的范围是 [-1000, 1000] ,且整数 k 的范围是 [-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;
}
}