[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.
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.
Thought process:
If we continue to use prefix sum, update() will take O(n). To reduce the time complexity, use binary indexed tree or segment tree instead.
Solution 1 (Binary indexed tree):
Solution 1 (Binary indexed tree):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | class NumArray { private int[] nums; private int[] tree; public NumArray(int[] nums) { int len = nums.length; this.nums = new int[len]; tree = new int[len + 1]; for (int i = 0; i < len; i++) { update(i, nums[i]); } } public void update(int i, int val) { int diff = val - nums[i]; nums[i] = val; for (int j = i + 1; j < tree.length; j += (j & -j)) { tree[j] += diff; } } public int sumRange(int i, int j) { return sum(j) - sum(i - 1); } private int sum(int i) { int sum = 0; for (int j = i + 1; j > 0; j -= (j & -j)) { sum += tree[j]; } return sum; } } /** * 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); */ |
Solution 2 (Segment tree - recursive):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | class NumArray { private int[] tree; private int len; public NumArray(int[] nums) { len = nums.length; tree = new int[(int) Math.pow(2, Math.ceil(Math.log(len) / Math.log(2)) + 1)]; if (len == 0) { return; } buildTree(nums, 1, 0, len - 1); } public void update(int i, int val) { update(i, val, 1, 0, len - 1); } public int sumRange(int i, int j) { return sumRange(i, j, 1, 0, len - 1); } private void buildTree(int[] nums, int index, int left, int right) { System.out.println(index + ", " + left + ", " + right); if (left == right) { tree[index] = nums[left]; return; } int mid = left + (right - left) / 2; buildTree(nums, index * 2, left, mid); buildTree(nums, index * 2 + 1, mid + 1, right); tree[index] = tree[index * 2] + tree[index * 2 + 1]; } private int sumRange(int i, int j, int index, int left, int right) { if (i > right || j < left) { return 0; } if (i <= left && j >= right) { return tree[index]; } int mid = left + (right - left) / 2; return sumRange(i, j, index * 2, left, mid) + sumRange(i, j, index * 2 + 1, mid + 1, right); } private void update(int i, int val, int index, int left, int right) { if (left == right) { tree[index] = val; return; } int mid = left + (right - left) / 2; if (i <= mid) { update(i, val, index * 2, left, mid); } else { update(i, val, index * 2 + 1, mid + 1, right); } tree[index] = tree[index * 2] + tree[index * 2 + 1]; } } /** * 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); */ |
Solution 3 (Segment tree - iterative):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | class NumArray { private int[] tree; private int len; public NumArray(int[] nums) { len = nums.length; if (len == 0) { return; } tree = new int[len * 2]; buildTree(nums); } public void update(int i, int val) { i += len; tree[i] = val; while (i > 0) { int left = i; int right = i; if (i % 2 == 0) { right = i + 1; } else { left = i - 1; } tree[i / 2] = tree[left] + tree[right]; i /= 2; } } public int sumRange(int i, int j) { i += len; j += len; int sum = 0; while (i <= j) { if (i % 2 == 1) { sum += tree[i]; i++; } if (j % 2 == 0) { sum += tree[j]; j--; } i /= 2; j /= 2; } return sum; } private void buildTree(int[] nums) { for (int i = len, j = 0; i < tree.length; i++, j++) { tree[i] = nums[j]; } for (int i = len - 1; i > 0; i--) { tree[i] = tree[i * 2] + tree[i * 2 + 1]; } } } /** * 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); */ |
Time complexity:
- Constructor: O(n).
- update: O(logn).
- sumRange: O(logn).
Comments
Post a Comment