Q:
Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.
Example:
Given nums = [-2, 0, 3, -5, 2, -1] sumRange(0, 2) -> 1 sumRange(2, 5) -> -1 sumRange(0, 5) -> -3
Note:
You may assume that the array does not change. There are many calls to sumRange function.
public NumArray(int[] nums) {
}
public int sumRange(int i, int j) {
}
// Your NumArray object will be instantiated and called as such:
// NumArray numArray = new NumArray(nums);
// numArray.sumRange(0, 1);
// numArray.sumRange(1, 2);
}
注:求的是range内所有数的总和。
#A:
这个BF比较直观,但时间复杂度不是最优。因为有个for loop,所以时间复杂度是O(n)。
Q:为什么这个会Time Limit Exceeded(超时)?
如果array里面数字少,算range sum其实还好,效率应该是不错的吧!?但是如果数字大了,最极限的情况,比如 `int[] test = new int[1000000];`那要是我们求`.sumRange(3,999999)`,loop trace基本无限趋近于O(n)了。所以,放大测试,就会发现问题。
private int[] data;
public NumArray(int[] nums) {
data = nums; //data is reference
}
public int sumRange(int i, int j) {
int sum = 0;
for (int k = i; k <= j; k++) { //这里有个for loop, 所以时间复杂度:O(n)
sum += data[k];
}
return sum;
}
这个最优,时间复杂度O(1),空间复杂度O(n)
public class NumArray {
int[] nums;
public NumArray(int[] nums) { //pre-caculation
this.nums = nums;
for(int i = 1; i < nums.length; i++)
nums[i] += nums[i - 1];
}
public int sumRange(int i, int j) {
if(i == 0) //这个if判断不能省略
return nums[j];
else
return nums[j] - nums[i - 1];
}
}
思路同上,但加入dummy 0,省去if判断
private int[] sum;
public NumArray(int[] nums) {
sum = new int[nums.length + 1];
for (int i = 0; i < nums.length; i++) {
sum[i + 1] = sum[i] + nums[i];
}
}
public int sumRange(int i, int j) {
return sum[j + 1] - sum[i];
}
这个处理起来有点儿绕,要多declaration一个array。另外毕竟length不一样,要加1。
优点是不需要if判断了。原作者是这么解释的:
>Notice in the code above we inserted a dummy 0 as the first element in the *sum* array. This trick saves us from an extra conditional check in *sumRange*function.
**Complexity analysis** :Time complexity : O(1),Space complexity : O(n)
O(n) time pre-computation. Since the cumulative sum is cached, each *sumRange* query can be calculated in O(1).
----
LeetCode editorial solution approach #2
private Map<Pair<Integer, Integer>, Integer> map = new HashMap<>();
public NumArray(int[] nums) {
int sum = 0;
for (int i = 0; i < nums.length; i++) {
for (int j = i; j < nums.length; j++) {
sum += nums[j];
map.put(Pair.create(i, j), sum);
}
}
}
public int sumRange(int i, int j) {
return map.get(Pair.create(i, j));
}
用到了HashMap,~~还得自己定义对象Pair~~,**map可以当做一个容器(装载具有一定格式的数据);pair可以理解为元素(放入到容器的的一个个个体),发现pair并没有单独行动的典型用法,正常都是配合map来使用(即把pair这个元素插入到map这个容器里面)。pair 是 一种模版类型。每个pair 可以存储两个值。这两种值无限制。也可以将自己写的struct的对象放进去,去处理一对儿不同类型的值。** LeetCode讨论里,貌似有人说程序用不了,可能是没有自己定义Pair类,Java标准库里没有这个类,这个数据类型得自己定义一下才能用吧。貌似C++可以直接用,除非是两个值数据类型不同,才得自己写个struct。(这块儿不是100%确定...):| `Map<Pair<Integer, Integer>, Integer>`,并且需要一个O(n^2)的pre-computation,因为要put数据到一个二维map里。但是每个sumRange query的时间是O(1),HashTable的look up运行时长是个定值。
----
#Notes:
----
**好像**:当"pre-computation done in the constructor",在考虑sumRange方法的query's time,计算这个方法(算法)的时间复杂度时,pre- 部分可以不计入。
###Dynamic Programming(动态规划):
- 线性动规
- 区域动规
- 树形动规
- 背包问题