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:

  1. The array is only modifiable by the update function.
  2. You may assume the number of calls to update and sumRange function is distributed evenly.
class NumArray {
    List<Integer> list = new ArrayList();
    
    public NumArray(int[] nums) {
        for(int i: nums) list.add(i);   
    }
    
    public void update(int i, int val) {
        list.set(i, val);
    }
    
    public int sumRange(int i, int j) {
        int res = 0;
        for(int m = i; m <= j; m++) res+=list.get(m);
        return res;
    }
}
public class NumArray {

    class SegmentTreeNode {
        int start, end;
        SegmentTreeNode left, right;
        int sum;

        public SegmentTreeNode(int start, int end) {
            this.start = start;
            this.end = end;
            this.left = null;
            this.right = null;
            this.sum = 0;
        }
    }
      
    SegmentTreeNode root = null;
   
    public NumArray(int[] nums) {
        root = buildTree(nums, 0, nums.length-1);
    }

    private SegmentTreeNode buildTree(int[] nums, int start, int end) {
        if (start > end) {
            return null;
        } else {
            SegmentTreeNode ret = new SegmentTreeNode(start, end);
            if (start == end) {
                ret.sum = nums[start];
            } else {
                int mid = start  + (end - start) / 2;             
                ret.left = buildTree(nums, start, mid);
                ret.right = buildTree(nums, mid + 1, end);
                ret.sum = ret.left.sum + ret.right.sum;
            }         
            return ret;
        }
    }
   
    void update(int i, int val) {
        update(root, i, val);
    }
   
    void update(SegmentTreeNode root, int pos, int val) {
        if (root.start == root.end) {
           root.sum = val;
        } else {
            int mid = root.start + (root.end - root.start) / 2;
            if (pos <= mid) {
                 update(root.left, pos, val);
            } else {
                 update(root.right, pos, val);
            }
            root.sum = root.left.sum + root.right.sum;
        }
    }

    public int sumRange(int i, int j) {
        return sumRange(root, i, j);
    }
    
    public int sumRange(SegmentTreeNode root, int start, int end) {
        if (root.end == end && root.start == start) {
            return root.sum;
        } else {
            int mid = root.start + (root.end - root.start) / 2;
            if (end <= mid) {
                return sumRange(root.left, start, end);
            } else if (start >= mid+1) {
                return sumRange(root.right, start, end);
            }  else {    
                return sumRange(root.right, mid+1, end) + sumRange(root.left, start, mid);
            }
        }
    }
}

Segment tree, 主要解决的是range sum,update等疑难杂症。意思是构建一个树,这个树的root是所有的sum,然后left child是左边的sum,right child是右边的sum,直到leaf node(单个数字的sum是它本身)。

Segment node里面有left,right代表左右child,start end代表这个node的sum是从哪开始,到哪结束,sum代表这一段的range sum。

build:构造的时候就像构造其他树,从mid开始,递归它的left,right,更新当前node的sum。

update:

 

 递归结束条件是到达最底层,更新这个position的结点的值,也就是更新它的sum。上层是根据当前位置选择进入左子树还是右子树,也要跟着更新所有的sum。

sumRange:有几种可能,1)mid ≥ end,比如数组是0-9,mid就是4,如果range sum是【0,2】,那就要进入到左子树。2)mid + 1 ≤ start,【5,6】,进入右子树。3)【3,5】,左右都要进去并返回对应的。

https://blog.csdn.net/yuzhiqiang666/article/details/80643017

https://leetcode.com/problems/range-sum-query-mutable/discuss/75724/17-ms-Java-solution-with-segment-tree

posted @ 2020-05-09 09:46  Schwifty  阅读(139)  评论(0编辑  收藏  举报