Skip to content

Latest commit

 

History

History
executable file
·
340 lines (312 loc) · 8.45 KB

307. Range Sum Query - Mutable.md

File metadata and controls

executable file
·
340 lines (312 loc) · 8.45 KB

307. Range Sum Query - Mutable

Question

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

Thinking:

  • Method 1: 通过数组存储数据。
class NumArray {
    private int[] nums;
    public NumArray(int[] nums) {
        this.nums = nums;
    }

    public void update(int i, int val) {
        nums[i] = val;
    }

    public int sumRange(int i, int j) {
        int sum = 0;
        for(; i <= j; i++)
            sum += this.nums[i];
        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);
 */
  • Method 2: 保存从0加到当前数的和
class NumArray {
    private int[] sum;
    public NumArray(int[] nums) {
        this.sum = new int[nums.length];
        int count = 0;
        for(int i = 0; i < nums.length; i++){
            count += nums[i];
            sum[i] = count;
        }
    }

    public void update(int i, int val) {
        int old = i > 0? (sum[i] - sum[i - 1]): sum[0];
        int diff = val - old;
        for(int j = i; j < sum.length; j++){
            sum[j] += diff;
        }
    }

    public int sumRange(int i, int j) {
        if(i == 0) return sum[j];
        else
            return sum[j] - sum[i - 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);
 */

Second time

  1. Use binary index tree
class NumArray {
    private int[] c;
    private int[] nums;
    private int lowBit(int n){
        return n & (-n);
    }
    public NumArray(int[] nums) {
        c = new int[nums.length + 1];
        this.nums = nums;
        for(int i = 1; i <= nums.length; i++){
            int lowBit = lowBit(i);
            int sum = 0;
            for(int j = i - lowBit + 1; j <= i; j++){
                sum += nums[j - 1];
            }
            c[i] = sum;
        }
    }
    public void update(int i, int val) {
        int diff = val - nums[i];
        nums[i] = val;
        int index = i + 1;
        while(index <= this.nums.length){
            c[index] += diff;
            index += lowBit(index);
        }
    }
    public int sumRange(int i, int j) {
        int sum1 = 0;
        int index1 = i;
        while(index1 > 0){
            sum1 += c[index1];
            index1 -= lowBit(index1);
        }
        int sum2 = 0;
        int index2 = j + 1;
        while(index2 > 0){
            sum2 += c[index2];
            index2 -= lowBit(index2);
        }
        return sum2 - sum1;
    }
}
/**
 * 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);
 */
  1. Use segment tree to solve this question.
class NumArray {
    private int[] segment;
    private int[] nums;
    public NumArray(int[] nums) {
        this.segment = new int[nums.length << 2 + 1];
        this.nums = nums;
        if(nums != null && nums.length != 0)    build(1, nums.length, 1);
    }
    private void build(int l, int r, int k){
        if(l == r){
            segment[k] = this.nums[l - 1];
        }else{
            int m = l + ((r - l) >> 1);
            build(l, m, k << 1);
            build(m + 1, r, k << 1 | 1);
            segment[k] = segment[k << 1] + segment[k << 1 | 1];
        }
    }
    public void update(int i, int val) {
        update(i + 1, val - this.nums[i], 1, this.nums.length, 1);
        this.nums[i] = val;
    }
    private void update(int i, int diff, int l, int r, int k){
        if(l == r) segment[k] += diff;
        else{
            int mid = l + ((r - l) >> 1);
            if(i <= mid)    update(i, diff, l, mid, k << 1);
            else    update(i, diff, mid + 1, r, k << 1 | 1);
            segment[k] = segment[k << 1] + segment[k << 1 | 1];
        }
    }
    public int sumRange(int i, int j) {
        return sum(i + 1, j + 1, 1, this.nums.length, 1);
    }
    private int sum(int L, int R, int l, int r, int k){
        if(L <= l && R >= r) return segment[k];
        else{
            int m = l + ((r - l) >> 1);
            int sum = 0;
            if(L <= m) sum += sum(L, R, l, m, k << 1);
            if(R > m) sum += sum(L, R, m + 1, r, k << 1 | 1);
            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);
 */

Third time

  1. BIT
class NumArray {
    private int[] nums;
    private int[] bit;

    private int lowBit(int x){
        return x & (-x);
    }
    public NumArray(int[] nums) {
        this.nums = new int[nums.length + 1];
        for(int i = 0; i < nums.length; i++){
            this.nums[i + 1] = nums[i];
        }
        this.bit = new int[nums.length + 1];
        for(int i = 1; i < this.nums.length; i++){
            for(int j = i - lowBit(i) + 1; j <= i; j++)
                this.bit[i] += this.nums[j];
        }
    }

    public void update(int i, int val) {
        int diff = val - nums[i + 1];
        nums[i + 1] = val;
        int index = i + 1;
        while(index < nums.length){
            bit[index] += diff;
            index += lowBit(index);
        }
    }

    private int sum(int i){
        int sum = 0;
        while(i > 0){
            sum += bit[i];
            i -= lowBit(i);
        }
        return sum;
    }    
    public int sumRange(int i, int j) {
        return sum(j + 1) - sum(i);
    }
}

/**
 * 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);
 */
  1. Segment Tree
class NumArray {
    private int[] nums;
    private int[] segment;
    public NumArray(int[] nums) {
        if(nums == null || nums.length == 0) return;
        this.nums = nums;
        this.segment = new int[nums.length << 2 + 1];
        insert(1, nums.length, 1);
    }
    private void insert(int l, int r, int k){
        if(l == r) segment[k] = nums[l - 1];
        else{
            int m = l + ((r - l) >> 1);
            insert(l, m, k << 1);
            insert(m + 1, r, k << 1 | 1);
            segment[k] = segment[k << 1] + segment[k << 1 | 1];
        }
    }
    
    public void update(int i, int val) {
        update(i, val - nums[i], 1, nums.length, 1);
        this.nums[i] = val;
    }
    private void update(int i, int diff, int l, int r, int k){
        if(l == r) segment[k] += diff;
        else{
            int m = l + ((r - l) >> 1);
            if((i + 1) <= m) update(i, diff, l, m, k << 1);
            if((i + 1) > m) update(i , diff, m + 1, r, k << 1 | 1);
            segment[k] = segment[k << 1] + segment[k << 1 | 1];
        }
    }
    
    public int sumRange(int i, int j) {
        return sumRange(i + 1, j + 1, 1, this.nums.length, 1);
    }
    private int sumRange(int L, int R, int l, int r, int k){
        if(l >= L && r <= R) return segment[k];
        else{
            int m = l + ((r - l) >> 1);
            int sum = 0;
            if(L <= m) sum += sumRange(L, R, l, m, k << 1);
            if(R > m) sum += sumRange(L, R, m + 1, r, k << 1 | 1);
            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);
 */

C++ Version

class NumArray {
private:
    vector<int> sum_;
    vector<int> nums_;
public:
    NumArray(vector<int>& nums): nums_(std::move(nums)) {
        int size = nums_.size();
        if(size == 0) return;
        sum_.resize(size, 0);
        sum_[0] = nums_[0];
        for(int i = 1; i < size; i++){
            sum_[i] = sum_[i - 1] + nums_[i];
        }
    }
    void update(int i, int val) {
        int pre = nums_[i];
        nums_[i] = val;
        int diff = val - pre;
        for(int j = i; j < sum_.size(); j++){
            sum_[j] += diff;
        }
    }
    int sumRange(int i, int j) {
        return sum_[j] - sum_[i] + nums_[i];
    }
};

/**
 * 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);
 */