Binary Indexed Tree(樹狀數(shù)組) / Segment Tree (線段樹)

Range Sum Query - Mutable (LeetCode)
多用于高效計算數(shù)列的前綴和, 區(qū)間和
在O(log n)時間內(nèi)得到任意前綴和,并同時支持在O(log n)時間內(nèi)動態(tài)單點值的修改

// Binary Indexed Tree 樹狀數(shù)組
// 86 ms
class NumArray {
public:
    NumArray(vector<int> nums) {
        array.resize(nums.size() + 1, 0); // Use array of length n + 1, ignoring index 0
        for (int i = 0; i < nums.size(); i++)
            add(i + 1, nums[i]);
    }

    void update(int i, int val) {
        int origin_val = sum(i + 1) - sum(i);
        add(i + 1, val - origin_val);
    }
    
    int sumRange(int i, int j) {
        return sum(j + 1) - sum(i);
    }
private:
    vector<int> array;
    void add(int i, int val) {
        while (i < array.size()) {
            array[i] += val;
            i += (i & -i); // Extract last set bit: x & (-x)
        }
    }
    int sum(int i) {
        int res = 0;
        while (i) {
            res += array[i];
            i -= (i & -i);
        }
        return res;
    }
};
// Segment Tree 線段樹
// 133 ms
class NumArray {
public:
    NumArray(vector<int> nums) {
        n = nums.size();
        if (n > 0) {
            // Height of segment tree
            int x = (int)(ceil(log2(n))); 
            // Maximum size of segment tree
            int max_size = 2 * (int)pow(2, x) - 1; 
            st.resize(max_size); // Important!: st.resize(2 * n - 1); 是錯誤的 因為線段樹不一定是完全二叉樹
            initialize(0, 0, n - 1, nums);
        }
    }
    
    void update(int i, int val) {
        int origin_val = sumRange(i, i);
        add(i, val - origin_val);
    }
    
    int sumRange(int i, int j) {
        return sumRange(0, i, j, 0, n - 1);
    }
private:
    int n;
    vector<int> st;
    int initialize(int idx, int l, int r, vector<int> &nums) {
        if (l == r) {
            st[idx] = nums[l];
        } else {
            int mid = (l + r) / 2;
            st[idx] = initialize(2 * idx + 1, l, mid, nums) + initialize(2 * idx + 2, mid + 1, r, nums);
        }
        return st[idx];
    }
    void add(int i, int val) {
        int l = 0, r = n - 1, idx = 0;
        while (l < r) {
            st[idx] += val;
            int mid = (l + r) / 2;
            if (i <= mid) {
                idx = 2 * idx + 1;
                r = mid;
            } else {
                idx = 2 * idx + 2;
                l = mid + 1;
            }
        }
        st[idx] += val;
    }
    int sumRange(int idx, int i, int j, int l, int r) {
        if (l > r || j < l || r < i)
            return 0;
        if (i <= l && r <= j)
            return st[idx];
        int mid = (l + r) / 2;
        return sumRange(idx * 2 + 1, i, j, l, mid) + sumRange(idx * 2 + 2, i, j, mid + 1, r);
    }
};

簡書原創(chuàng),轉(zhuǎn)載請聯(lián)系作者

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗。 張土汪:刷leetcod...
    土汪閱讀 12,899評論 0 33
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,872評論 25 709
  • 南枝登喜鵲,摯友又添郎, 苗植春風(fēng)里,明朝一棟梁。 好友今天來電說又生了一大胖兒子,故涂鴉幾句,賀之!
    夢之旅_926e閱讀 252評論 11 10
  • 如果有人問你最喜歡的網(wǎng)絡(luò)劇有沒有、是什么的話?我想很多人都會說《萬萬沒想到》。其實早前我也很喜歡這部無厘頭的輕喜劇...
    青木俠閱讀 1,097評論 2 2
  • 一、古代詩歌 1.詩按音律分,分為古體詩和近體詩兩類。古體詩和近體詩是唐代形成的概念,是從詩的音律角度來劃分的。 ...
    賽德傳播閱讀 3,032評論 0 1

友情鏈接更多精彩內(nèi)容