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.
题目大意:
给一个整数数组,对数组进行封装,提供对外接口
1.sumRange(i,j),求下标i到下标j之间所有元素之和
2.update(i, val),更新下标为i的元素为val值
思路一:
常规解法,便利[i,j]获取sum值,直接通过下标访问数组修改元素值,时间复杂度分别为O(N)和O(1)
1 public class NumArray { 2 private int nums[]; 3 4 public NumArray(int[] nums) { 5 this.nums = new int[nums.length]; 6 for(int i = 0; i < nums.length; i++){ 7 this.nums[i] = nums[i]; 8 } 9 } 10 11 void update(int i, int val) { 12 if(positionIsValid(i)) 13 nums[i] = val; 14 } 15 16 public int sumRange(int i, int j) { 17 if(i > j || !positionIsValid(i) || !positionIsValid(j)) 18 return -1; 19 int sum = 0; 20 for(int index = i; index <= j; index ++){ 21 sum += nums[index]; 22 } 23 24 return sum; 25 } 26 27 private boolean positionIsValid(int index){ 28 return (index >= 0 && index < nums.length); 29 } 30 }
超时
思路二:
根据提示,可以用分段树(segement tree)或者叫区间树,没用过。参考
http://bookshadow.com/weblog/2015/08/13/segment-tree-set-1-sum-of-given-range/
https://github.com/nanwan03/leetcode/blob/master/Algorithm/Range%20Sum%20Query%20-%20Mutable%20-%20Segment%20Tree.java
1 //分段树 2 class SegmentTreeNode{ 3 public int start; 4 public int end; 5 public SegmentTreeNode left; 6 public SegmentTreeNode right; 7 public int sum; 8 9 public SegmentTreeNode(int start, int end){ 10 this.start = start; 11 this.end = end; 12 sum = 0; 13 left = null; 14 right = null; 15 } 16 } 17 18 public class NumArray { 19 private SegmentTreeNode root; 20 21 public NumArray(int[] nums) { 22 root = buildSegmentTree(nums, 0, nums.length - 1); 23 } 24 25 //建造分段树 26 private SegmentTreeNode buildSegmentTree(int nums[], int start, int end){ 27 if(start > end) 28 return null; 29 else{ 30 SegmentTreeNode ret = new SegmentTreeNode(start, end); 31 if(start == end) 32 ret.sum = nums[start]; 33 else{ 34 int mid = start + (end - start) / 2; 35 SegmentTreeNode left = buildSegmentTree(nums, start, mid); 36 SegmentTreeNode right = buildSegmentTree(nums, mid + 1, end); 37 ret.sum = left.sum + right.sum; 38 ret.left = left; 39 ret.right = right; 40 }//else 41 42 return ret; 43 }//else 44 }//buildSegmentTree 45 46 //更新分段树节点的值 47 private void update(SegmentTreeNode root, int position, int val){ 48 if(root.start == root.end) 49 root.sum = val; 50 else{ 51 int mid = root.start + (root.end - root.start) / 2; 52 if(position <= mid){ 53 update(root.left, position, val); 54 }//if 55 else{ 56 update(root.right, position, val); 57 } //else 58 59 root.sum = root.left.sum + root.right.sum; 60 }//else 61 }//update segmentTree 62 63 void update(int i, int val) { 64 update(root, i, val); 65 } 66 67 private int sumRange(SegmentTreeNode root, int start, int end){ 68 if(root.start == start && root.end == end) 69 return root.sum; 70 else{ 71 int mid = root.start + (root.end - root.start) / 2; 72 if(mid >= end){ 73 return sumRange(root.left, start, end); 74 }else if(start >= mid + 1){ 75 return sumRange(root.right, start, end); 76 }else{ 77 return sumRange(root.left, start, mid) + sumRange(root.right, mid + 1, end); 78 } 79 } 80 } 81 82 public int sumRange(int i, int j) { 83 return sumRange(root, i, j); 84 } 85 }//NumArray
时间复杂度都为O(logn)
思路三:
使用树状数组,(binary index tree)里面有些需要数学推导,可以不用理会。参考
http://blog.csdn.net/lulipeng_cpp/article/details/7816527#comments
https://leetcode.com/discuss/96367/three-implementations-binary-segment-array-segment-comments
1 import java.util.Arrays; 2 3 //树状数组 4 public class NumArray { 5 int arr[]; 6 int bit[]; 7 int n; 8 9 public NumArray(int[] nums) { 10 n = nums.length; 11 arr = Arrays.copyOf(nums, n); 12 bit = new int[n + 1]; 13 for(int i = 0; i < arr.length; i++){ 14 updateBit(i + 1, arr[i]); 15 } 16 } 17 18 void update(int i, int val) { 19 int diff = val - arr[i]; 20 arr[i] = val; 21 updateBit(i + 1, diff); 22 } 23 24 public int sumRange(int i, int j) { 25 return getSum(j + 1) - getSum(i); 26 } 27 28 private void updateBit(int j, int diff){ 29 while(j <= n){ 30 bit[j] += diff; 31 j += j & (-j); 32 } 33 } 34 35 private int getSum(int j){ 36 int sum = 0; 37 while(j > 0){ 38 sum += bit[j]; 39 j -= j & (-j); 40 }//while 41 42 return sum; 43 } 44 }//NumArray
时间复杂度都为O(logn)