Leetcode: Range Sum Query - Mutable



Given an integer array nums, find the sum of the elements between indicesi and j (ij), 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

比较困难,主要是需要小于O(N)的时间复杂度。新的知识点,可以用树状数组(Binary Indexed Tree)或者线段树(Segment tree)来解决。


Binary Indexed Tree的特点 (from baidu): 每个节点x管辖的区间为2^k(其中k为x二进制末尾0的个数)个元素。求二进制最右边的1代表的数值可以用 (x & -x)。这样更新和求和都是log(N)的时间复杂度。

class NumArray {
public:
    NumArray(vector<int> &nums) {
        m_bitSums.resize(nums.size() + 1);
        m_origNums.resize(nums.size() + 1);
        for (int i = 0; i < nums.size(); ++i) {
            update(i, nums[i]);
        }
    }

    void update(int i, int val) {
        int delta = val - m_origNums[++i];
        m_origNums[i] = val;
        while (i < m_bitSums.size()) {
            m_bitSums[i] += delta;
            i += (i & -i);
        }
    }

    int sumRange(int i, int j) {
        return (i == j) ? m_origNums[i+1] : getSum(j+1) - getSum(i);
    }
    
private:
    int getSum(int i) {
        int result = 0;
        while (i > 0) {
            result += m_bitSums[i];
            i -= (i & -i);
        }
        
        return result;
    }

private:
    vector<int> m_bitSums;
    vector<int> m_origNums;
};


// Your NumArray object will be instantiated and called as such:
// NumArray numArray(nums);
// numArray.sumRange(0, 1);
// numArray.update(1, 10);
// numArray.sumRange(1, 2);

From baidu - Segment tree是一种二叉搜索树,具有平衡的特点。它将一个区间分割成单元区间,对应叶节点。线段树是建立在线段的基础上,每个结点都代表了一条线段[a,b]。长度为1的线段称为元线段。非元线段都有两个子结点,左结点代表的线段为[a,(a + b) / 2],右结点代表的线段为[((a + b) / 2)+1,b]。

struct SegmentNode {
    int start;
    int end;
    int sum;
    SegmentNode* left;
    SegmentNode* right;
    
    SegmentNode(int s, int e)
        : start(s), end(e), sum(0), left(nullptr), right(nullptr)
    {
    }
};

class NumArray {
public:
    NumArray(vector<int> &nums) {
        root = buildTree(nums, 0, nums.size() - 1);
    }

    void update(int i, int val) {
        updateTree(root, i, val);
    }

    int sumRange(int i, int j) {
        return sumTree(root, i, j);
    }
    
private:
    SegmentNode* buildTree(const vector<int>& nums, int start, int end) {
        if (start > end) {
            return nullptr;
        }
        
        SegmentNode* node = new SegmentNode(start, end);
        if (start == end) {
            node->sum = nums[start];
        }
        else {
            int mid = start + (end - start) / 2;
            node->left = buildTree(nums, start, mid);
            node->right = buildTree(nums, mid + 1, end);
            node->sum = node->left->sum + node->right->sum;
        }
        
        return node;
    }
    
    int updateTree(SegmentNode* root, int i, int val) {
        if (root == nullptr || i < root->start || i > root->end) {
            return 0;
        }
        if (root->start == i && root->end == i) {
            int diff = val - root->sum;
            root->sum = val;
            return diff;
        }

        int mid = root->start + (root->end - root->start) / 2;
        int diff = (i <= mid ? updateTree(root->left, i, val) : updateTree(root->right, i, val));
        root->sum += diff;
        return diff;
    }
    
    int sumTree(SegmentNode* root, int i, int j) {
        if (root == nullptr || i > root->end || j < root->start) {
            return 0;
        }
        if (i <= root->start && j >= root->end) {
            return root->sum;
        }
        
        int mid = root->start + (root->end - root->start) / 2;
        if (i > mid) {
            return sumTree(root->right, i, j);
        }
        else if (j <= mid) {
            return sumTree(root->left, i, j);
        }
        else {
            return sumTree(root->left, i, mid) + sumTree(root->right, mid + 1, j);
        }
    }

private:
    SegmentNode* root;
};


// Your NumArray object will be instantiated and called as such:
// NumArray numArray(nums);
// numArray.sumRange(0, 1);
// numArray.update(1, 10);
// numArray.sumRange(1, 2);


BIT效率高一些,但个人感觉Segment Tree写起来简单一些,不熟悉BIT算法。







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值