(LeetCode 307) Range Sum Query - Mutable(Segment Tree)

Q:
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:
The array is only modifiable by the update function.
You may assume the number of calls to update and sumRange function is distributed evenly.

題意大致是,給你提供一個二維數組,然後求指定下標之間的數之和,已知數組中的值可以更新,並且更新和求和操作會被頻繁調用

Solution;
別看這道題和上幾道題相似,解法其實完全不一樣, (LeetCode 303) Range Sum Query - Immutable
最原始的想法就是暴力遍歷求和,不過想也不用想,當求和操作操作頻繁調用,會超出給定時限。
並且,數組中的值會被頻繁更新,我瞭解到的解決方法有Segement Tree(線段樹),Binary Indexed Tree(樹狀數組) ,和平方根分解三種辦法。樹狀數組真的是神作,很精巧的辦法,也很高興能夠了解並學習這些數據結構。

我在這裏提供線段樹的解法,想了解樹狀數組的解法可以參考這篇博客:
(LeetCode 307) Range Sum Query - Mutable(樹狀數組講解)

線段樹,顧名思義,它的每一個結點代表一個區間。每個結點中包含的信息應該有該區間的起始下標start ,結束下標end ,左子樹指針left ,右子樹指針right ,以及我們需要計算的信息,如該區間的最大值max ,最小值min ,和sum 等等。
我們這道題就使用到了sum 這個信息,每個結點的左右子節點均分該結點區間,直到葉節點中的區間只含一個值。那麼我們創建樹的時間複雜度爲O(n) ,更新數的時間複雜度爲O(log(n)) ,求和的時間複雜度也是O(log(n))

class NumArray {
public:
    struct SegmentNode 
    {
        int start;
        int end;
        int sum;
        SegmentNode *left;
        SegmentNode *right;
        SegmentNode(int start, int end){
            this->start = start;
            this->end = end;
            this->sum = 0;
        }
    };

    SegmentNode *root;
    SegmentNode* buildTree(vector<int> &nums,int lo,int hi){
        if(hi<lo)return nullptr;
        SegmentNode *node = new SegmentNode(lo,hi);
        if(hi==lo){
            node->sum = nums[lo];
            return node;
        }
        int mid = (lo+hi)/2;
        node->left = buildTree(nums,lo,mid);
        node->right = buildTree(nums,mid+1,hi);
        node->sum = node->left->sum+node->right->sum;
        return node;
    }

    void update(SegmentNode *node, int po,int val){
        if(node->start==node->end&&node->start == po){
            node->sum = val;
            return;
        }
        if(po<node->start||po>node->end)
            return;
        int mid = (node->start+node->end)/2;
        if(po<=mid){
            update(node->left,po,val);
        }
        else{
            update(node->right,po,val);
        }
        node->sum = node->left->sum + node->right->sum;
    }

    int sumRange(SegmentNode *node, int lo, int hi){
        if(node->start==lo&&node->end ==hi)
            return node->sum;

        int mid = (node->start+node->end)/2;
        if(hi<=mid) return sumRange(node->left,lo,hi);
        else if(lo>mid) return sumRange(node->right,lo,hi);
        else return sumRange(node->left,lo,mid)+sumRange(node->right,mid+1,hi);
    }


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

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

    int sumRange(int i, int j) {
        return sumRange(root,i,j);
    }
};

不過時間消耗不那麼樂觀啊

Reference Link:
http://www.cnblogs.com/yrbbest/p/5056739.html

發佈了45 篇原創文章 · 獲贊 15 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章