303. 区域和检索 - 数组不可变
给定一个整数数组 nums,求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和,包含 i, j 两点。
示例:
给定 nums = [-2, 0, 3, -5, 2, -1],求和函数为 sumRange() sumRange(0, 2) -> 1 sumRange(2, 5) -> -1 sumRange(0, 5) -> -3
说明:
- 你可以假设数组不可变。
- 会多次调用 sumRange 方法。
局限性的思路:简单的记录传入的数组数据,根据要求的求和区间遍历求和,这样,求和操作的时间复杂度为O(n), 当数据量太大时,性能太差,提交leetcode后,会提示超时.
class NumArray {
private int[] data;
public NumArray(int[] nums) {
data = new int[nums.length];
for(int i=0; i<data.length; i++){
data[i]=nums[i];
}
}
public int sumRange(int i, int j) {
int sum=0;
for(int k=i; k<=j; k++){
sum = sum + data[k];
}
return sum;
}
}
/**
* Your NumArray object will be instantiated and called as such:
* NumArray obj = new NumArray(nums);
* int param_1 = obj.sumRange(i,j);
*/
思路一. 由于题目只涉及到区间内的简单的求和查询,可以采用一个简单的预处理来完成,在记录数据时,将他们的和记录下来,这样,在执行区间求和时,只需执行一步减法即可,求和时间复杂度为O(1).
class NumArray {
private int[] sum;
public NumArray(int[] nums) {
//采用预处理的方式,sum[0]=0, sum[i+1]=nums[0]+nums[1]+...+nums[i]
sum = new int[nums.length+1];
sum[0]=0;
for(int i=1; i<sum.length; i++){
sum[i]=sum[i-1]+nums[i-1];
}
}
public int sumRange(int i, int j) {
return sum[j+1]-sum[i];
}
}
/**
* Your NumArray object will be instantiated and called as such:
* NumArray obj = new NumArray(nums);
* int param_1 = obj.sumRange(i,j);
*/
思路二. 通过线段树来完成
class NumArray {
//用于将线段树左右节点数据融合处理,根据具体业务,由用户外部实现
private interface Merger<E> {
E merge(E a, E b);
}
//底层通过静态数组实现一个线段树
private class SegmentTree<E> {
private E[] data; //存储传入的数据的数组
private E[] tree; //底层实现树的数组
private Merger<E> merger; //实现具体业务的接口,这里是一个融合器
//构造函数
//构造线段树时,需要从外部传入一个融合器,即实现了Merger接口的对象,可以使用匿名内部类实现
public SegmentTree(E[] arr, Merger<E> merger){
//必须放在buildSegmentTree()前面,buildSe