首页 > 代码库 > Leetcode 307. Range Sum Query - Mutable
Leetcode 307. 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.
给定一个整型数组,找出数组下标i到j的元素的和。
给定一个更新操作,update(i,val)将第i个元素更新为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.
数组只能被update方法更改。
假设update和sumRange被均匀调用。
首先尝试用数组sums的第i个元素存储[0:i]的和,这样的话:sumRange的时间复杂度为O(1),由于每次update(i,val)都要更新下标i之后的sums,所以时间复杂度为O(n),由于update和sumRange被均匀调用,所以整个操作的时间复杂度为O(n);另外需要n个元素的存储空间。
这样的话,不出意外的TLE了。
考虑用二叉树存储部分和。
构造一个完全二叉树,最后一层存储原始数组元素,其余每一层存储下一层对应左右孩子节点之和,使用二维数组tree[][]存储这颗完全二叉树,tree[0]存储原始数组,tree[i][j]存储tree[i-1][j*2]和tree[i-1][j*2+1]之和,其中i>0,j>=0;
sumRange(i,j)的求法:
由于i<=j,所以只需要同时从tree[0][i]和tree[0][j]向上遍历到最近的共同祖先节点pf即可,搜索过程中以s1记录以pf为根的这棵树中i之前所有元素之和,以s2记录j之前所有元素之和,最后结果就是:s2-s1+tree[0][i];
s1的更新方法:
若当前遍历的节点i‘为父节点i‘‘的右孩子,则另s1加上i‘‘左孩子的值;若为左孩子则不需要更新;
s2的更新方法:
若当前遍历的节点j‘为父节点j‘‘的右孩子,则另s2加上j‘‘左孩子的值;若为左孩子则不需要更新;
update(i,val)的操作:
依次按tree[0][i],tree[1][i/2],...的顺序一直更新到根节点即可;
复杂度:
sumRange和update最多遍历次数均为logn次,空间复杂度为O(n);
class NumArray { private: vector<vector<int>> tree; int rows, cols; public: NumArray(vector<int> &nums) { int r = 0, c = nums.size(); if ((cols = c) == 0) { rows = 0; return; } tree.push_back(nums); while (1) { int size = tree[r].size(); if (size == 1) break; vector<int> sums; for (int i = 0;i < size;i += 2) { if (i + 1 < size) sums.push_back(tree[r][i] + tree[r][i + 1]); else sums.push_back(tree[r][i]); } tree.push_back(sums); ++r; } rows = r + 1; } void update(int i, int val) { int delta = val - tree[0][i]; for (int j = 0;j < rows;++j) { tree[j][i] += delta; i = i / 2; } } int sumRange(int i, int j) { if (i < 0 || i >= cols || j < 0 || j >= cols) return 0; int r, s1, s2, i0, i_, j_; r = 0; s1 = tree[r][i]; s2 = tree[r][j]; i0 = i; while (i != j) { i_ = i / 2; j_ = j / 2; if (i_ * 2 + 1 == i) // i is the right child of his parent { s1 += tree[r][i - 1]; } if (j_ * 2 + 1 == j) // j is the right child of his parent { s2 += tree[r][j - 1]; } ++r; i = i_; j = j_; } return s2 - s1 + tree[0][i0]; } };
本文出自 “丁志新的博客” 博客,谢绝转载!
Leetcode 307. Range Sum Query - Mutable