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(動態規劃):
- 線性動規
- 區域動規
- 樹形動規
- 背包問題