Description
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.
思路
解法一
暴力。
时间复杂度:
- 构造数组:O(n)
- update操作:O(1)
- sumRange操作:O(n)
空间复杂度:O(n)
耗时 216 ms, faster than 21%, Memory 16.6 MB
class NumArray {
public:
NumArray(const vector<int> &numbers) : nums(numbers) {}
void update(int i, int val) {
nums[i] = val;
}
int sumRange(int i, int j) {
int sum = 0;
while (i <= j) {
sum += nums[i];
++i;
}
return sum;
}
private:
vector<int> nums;
};
/**
* Your NumArray object will be instantiated and called as such:
* NumArray* obj = new NumArray(nums);
* obj->update(i,val);
* int param_2 = obj->sumRange(i,j);
*/
解法二
线段树,本质是使用二分法拆分可变区间。
线段树是一颗可以携带额外信息的满二叉树,比如携带子树的结点和,或者最大值,最小值等等,这样,当某个结点的值发生变化时,只需要更新一下其所有祖先结点的信息,而并不需要更新整棵树,这样就极大的提高了效率。
这是我第一次实现线段树,比较吃力,解题思路参照的是这个博客:[LeetCode] 307. Range Sum Query - Mutable 区域和检索 - 可变
时间复杂度:
- 建树:O(n)
- update操作:O(lgn)
- sumRange操作:O(lgn)
空间复杂度:O(n)
耗时 48 ms, faster than 71.15%, Memory 16.7 MB
// nums 1 3 5 7
// tree 0 16 4 12 1 3 5 7
// i 0 1 2 3 4 5 6 7
//
// 1 3 5 7 9
// 0 25 17 8 16 1 3 5 7 9
// 0 1 2 3 4 5 6 7 8 9
class NumArray {
public:
NumArray(const vector<int> &nums) {
n = nums.size();
tree.resize(2 * nums.size(), 0);
build_seg_tree(nums);
}
void build_seg_tree(const vector<int> &nums) {
for (int i = 0; i < nums.size(); ++i) {
tree[i + n] = nums[i];
}
for (int i = n - 1; i > 0; --i) {
tree[i] = tree[2 * i] + tree[2 * i + 1];
}
}
void update(int i, int val) {
int idx = n + i; // position of nums[i] in tree
if (tree[idx] == val) return;
tree[idx] = val;
// update value of parent node
while (idx > 0 && idx / 2 != 0) {
int another_son_idx = idx ^ 1;
int parent_idx = idx / 2;
tree[parent_idx] = tree[idx] + tree[another_son_idx];
idx /= 2;
}
}
int sumRange(int i, int j) {
i += n;
j += n;
int sum = 0;
while (i <= j) {
if ((i & 1) == 1) { // element is right son of subtree or parent node
sum += tree[i];
++i; // move to a subtree on the right
}
if ((j & 1) == 0) { // element is left son of subtree or parent node
sum += tree[j];
--j; // move to a subtree on the left
}
// move to the parent node
i /= 2;
j /= 2;
}
return sum;
}
private:
int n; // numbers of element in nums
vector<int> tree;
};
/**
* Your NumArray object will be instantiated and called as such:
* NumArray* obj = new NumArray(nums);
* obj->update(i,val);
* int param_2 = obj->sumRange(i,j);
*/