題目鏈接:Range Sum Query - Mutable
題目內容:
Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.
The update(i, val) function modifies nums by updating the element at index i to val.
Example:
Given nums = [1, 3, 5]
sumRange(0, 2) -> 9
update(1, 2)
sumRange(0, 2) -> 8
Note:
The array is only modifiable by the update function.
You may assume the number of calls to update and sumRange function is distributed evenly.
題目解法:
題目要求快速的處理數組的部分和,因此很容易聯想到樹狀數組,樹狀數組是一種用於通過輔助數組和位置算法實現動態管理部分和的一種算法,其核心函數爲lowbit、add、sum,當我們需要加入一個元素時,使用add函數向某個位置注入值,當需要求0~某位置的和時,調用sum函數傳入這個位置即可,樹狀數組的代碼簡潔但是難以理解,所以建議採用背誦的方式,樹狀數組的實現如下。
int lowbit(int pos){
return pos&(-pos);
}
void add(int pos, int value){
while(pos < c.size()){
c[pos] += value;
pos += lowbit(pos);
}
}
int sum(int pos){
int res = 0;
while(pos > 0){
res += c[pos];
pos -= lowbit(pos);
}
return res;
}
其中c就是輔助數組。需要注意的是樹狀數組的索引必須從1開始,因此在與題目的輸入量相轉化時,需要把索引+1作爲樹狀數組的索引。
用法舉例
假設我們有數組arr:{1,2,3},要求部分和,我們先把這些值通過add注入樹狀數組,一定要注意索引+1.for(int i = 0; i < 3; i++){ add(i+1,arr[i]); // 把arr[i]添加到樹狀數組的i+1位置 }
操作完成後,樹狀數組就建立好了,下面就可以利用sum來求和了。例如我們需要arr中索引0~2的和,那麼使用sum(3)即可,如果要求1~2的和,可以用sum(3)-sum(0),注意到,sum(0)對於樹狀數組是一個非法索引,但是通過觀察sum函數發現pos=0正好返回0,也就是到這個位置的和爲0,滿足要求,不必特殊處理。
- 總結
綜上所述,要求arr中i~j的部分和,使用sum(j+1)-sum(i)即可。 值的更新問題
題目還要求使用update函數更新arr中位置i的值爲val,這就要利用add函數來實現,注意add函數是在位置pos上追加一個值value,而不是覆蓋,因此我們需要計算值的變化量,把它追加到相應位置,並且一定要記得更新arr,否則下次得到的變化量是錯誤的。void update(int i, int val) { int ori = m_nums[i]; // m_nums是拷貝arr數組所得的成員變量 int delta = val - ori; m_nums[i] = val; add(i+1,delta); }
具體實現
通過上面的討論,解決了每個部分的問題,就可以寫出解決此問題的具體代碼了,代碼如下。class NumArray { private: vector<int> c; vector<int> m_nums; public: NumArray(vector<int> &nums) { c.resize(nums.size()+1); m_nums = nums; for(int i = 0; i < nums.size(); i++){ add(i+1,nums[i]); } } int lowbit(int pos){ return pos&(-pos); } void add(int pos, int value){ while(pos < c.size()){ c[pos] += value; pos += lowbit(pos); } } int sum(int pos){ int res = 0; while(pos > 0){ res += c[pos]; pos -= lowbit(pos); } return res; } void update(int i, int val) { int ori = m_nums[i]; int delta = val - ori; m_nums[i] = val; add(i+1,delta); } int sumRange(int i, int j) { return sum(j+1) - sum(i); } };