Leetcode: Range Sum Query - Mutable

来源:互联网 发布:淘宝上签证怎么办理 编辑:程序博客网 时间:2024/05/01 23:43


Given an integer array nums, find the sum of the elements between indicesi andj (ij), inclusive.

The update(i, val) function modifies nums by updating the element at indexi toval.

Example:

Given nums = [1, 3, 5]sumRange(0, 2) -> 9update(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
原创粉丝点击