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]

  1. sumRange(0, 2) -> 9
  2. update(1, 2)
  3. 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.

    分析

由于需要求任意段的和,且会随机修改元素,用线段树(Segment Tree)再合适不过了。

另外一个数据结构,树状数组(Binary Indexed Tree),也适合解这道题。

解法1 线段树

  1. // Range Sum Query - Mutable
  2. // Segment Tree
  3. public class NumArray {
  4. private SegmentTreeNode root;
  5. // Time Complexity: O(n)
  6. public NumArray(int[] nums) {
  7. this.root = buildTree(nums, 0, nums.length);
  8. }
  9. // Time Complexity: O(log n)
  10. void update(int i, int val) {
  11. updateHelper(this.root, i, val);
  12. }
  13. // Time Complexity: O(log n)
  14. public int sumRange(int i, int j) {
  15. return sumRangeHelper(this.root, i, j+1);
  16. }
  17. private static SegmentTreeNode buildTree(int[] nums, int begin, int end) {
  18. if (nums == null || nums.length == 0 || begin >= end)
  19. return null;
  20. if (begin == end - 1) // one element
  21. return new SegmentTreeNode(begin, end, nums[begin]);
  22. final SegmentTreeNode root = new SegmentTreeNode(begin, end);
  23. final int middle = begin + (end - begin) / 2;
  24. root.left = buildTree(nums, begin, middle);
  25. root.right = buildTree(nums, middle, end);
  26. root.sum = root.left.sum + root.right.sum;
  27. return root;
  28. }
  29. private static void updateHelper(SegmentTreeNode root, int i, int val) {
  30. if (root.begin == root.end - 1 && root.begin == i) {
  31. root.sum = val;
  32. return;
  33. }
  34. final int middle = root.begin + (root.end - root.begin) / 2;
  35. if (i < middle) {
  36. updateHelper(root.left, i, val);
  37. } else {
  38. updateHelper(root.right, i, val);
  39. }
  40. root.sum = root.left.sum + root.right.sum;
  41. }
  42. private static int sumRangeHelper(SegmentTreeNode root, int begin, int end) {
  43. if (root == null || begin >=root.end || end <= root.begin)
  44. return 0;
  45. if (begin <= root.begin && end >= root.end)
  46. return root.sum;
  47. final int middle = root.begin + (root.end - root.begin) / 2;
  48. return sumRangeHelper(root.left, begin, Math.min(end, middle)) +
  49. sumRangeHelper(root.right, Math.max(middle, begin), end);
  50. }
  51. static class SegmentTreeNode {
  52. private int begin;
  53. private int end;
  54. private int sum;
  55. private SegmentTreeNode left;
  56. private SegmentTreeNode right;
  57. public SegmentTreeNode(int begin, int end, int sum) {
  58. this.begin = begin;
  59. this.end = end;
  60. this.sum = sum;
  61. }
  62. public SegmentTreeNode(int begin, int end) {
  63. this(begin, end, 0);
  64. }
  65. }
  66. }

解法2 树状数组

  1. // Range Sum Query - Mutable
  2. // Binary Indexed Tree
  3. public class NumArray {
  4. private int[] nums;
  5. private int[] bit;
  6. // Time Complexity: O(n)
  7. public NumArray(int[] nums) {
  8. // index 0 is unused
  9. this.nums = new int[nums.length + 1];
  10. this.bit = new int[nums.length + 1];
  11. for (int i = 0; i < nums.length; ++i) {
  12. update(i, nums[i]);
  13. }
  14. }
  15. // Time Complexity: O(log n)
  16. public void update(int index, int val) {
  17. final int diff = val - nums[index + 1];
  18. for (int i = index + 1; i < nums.length; i += lowbit(i)) {
  19. bit[i] += diff;
  20. }
  21. nums[index + 1] = val;
  22. }
  23. // Time Complexity: O(log n)
  24. public int sumRange(int i, int j) {
  25. return read(j + 1) - read(i);
  26. }
  27. private int read(int index) {
  28. int result = 0;
  29. for (int i = index; i > 0; i -= lowbit(i)) {
  30. result += bit[i];
  31. }
  32. return result;
  33. }
  34. private static int lowbit(int x) {
  35. return x & (-x); // must use parentheses
  36. }
  37. }

相关题目

原文: https://soulmachine.gitbooks.io/algorithm-essentials/content/java/binary-tree/segment-tree/range-sum-query-mutable.html