Range Sum Query

https://leetcode.com/problems/range-sum-query-mutable/

因为数组会变动,所以缓存机制受到了挑战。。。每次更新数组意味着缓存失效,这样一更新一查找的话相当于每次都重新计算了。

所以要设计一个更好的缓存机制,尽量降低更新带来的影响。

我选择分段缓存,就是把原数组的缓存分别放在多段缓存里,这样数组变动的时候只用更新一段缓存。

我选择分成log(n) 个段,并没有什么道理。

这样在查询rangeSum 的时候就复杂了,如果范围在同一个缓存段内就很好,当跨越缓存段的时候,要分别处理两头的两个段,然后还别忘了中间被跨越的那些段。

因为比较菜,实现得非常繁琐。但是终归accpeted 了

/**
 * @constructor
 * @param {number[]} nums
 */
var NumArray = function(nums) {
    this.nums = nums;
    this.cache = [];

    var cacheSize = 0;
    var numsLen = nums.length;
    while (numsLen > 0) {
        cacheSize++;
        numsLen = numsLen >> 1;
    }
    
    this.cacheSize = cacheSize;
    this.segSize = Math.floor(nums.length / cacheSize);

    var idx = 0;
    for (var i = 0; i < cacheSize; i++) {
        var cacheStart = idx;
        var segSize = this.segSize;
        if (i === cacheSize - 1) {
            segSize = Math.max(Math.floor(nums.length / cacheSize), nums.length - idx);
        }
        var cacheEnd = idx + segSize - 1;

        var thatCache = [];
        var thatAcc = 0;
        for (var j = cacheStart; j <= cacheEnd; j++) {
            thatAcc += this.nums[j];
            thatCache.push(thatAcc);
        }
        this.cache.push(thatCache);
        idx = cacheEnd + 1;
    }
};

/**
 * @param {number} i
 * @param {number} val
 * @return {void}
 */
NumArray.prototype.update = function(i, val) {
    var residual = val - this.nums[i];
    var cachePos = Math.min(Math.floor(i / this.segSize), this.cacheSize);
    this.nums[i] = val;
    var cache = this.cache[cachePos];
    var idx = i - cachePos * this.segSize;
    for (var j = idx; j < cache.length; j++) {
        cache[j] += residual;
    }
};

/**
 * @param {number} i
 * @param {number} j
 * @return {number}
 */
NumArray.prototype.sumRange = function(i, j) {
    if (this.cache.length === 0) return 0;
    var cachePosi = Math.min(Math.floor(i / this.segSize), this.cacheSize - 1);
    var cachePosj = Math.min(Math.floor(j / this.segSize), this.cacheSize - 1);
    if (cachePosi === cachePosj) {
        var cache = this.cache[cachePosi];
        var local_i = i - cachePosi * this.segSize;
        var local_j = j - cachePosi * this.segSize;
        return cache[local_j] - cache[local_i] + this.nums[i];
    } else {
        var cache_i = this.cache[cachePosi];
        var cache_j = this.cache[cachePosj];

        var local_i = i - cachePosi * this.segSize;
        var local_j = j - cachePosj * this.segSize;

        var ret_i = cache_i[cache_i.length - 1] - cache_i[local_i] + this.nums[i];
        var ret_j = cache_j[local_j];

        var ret = 0;
        for (var k = cachePosi + 1; k < cachePosj; k++) {
            ret += this.cache[k][this.cache[k].length - 1];
        }
        return ret + ret_i + ret_j;
    }
};
原文地址:https://www.cnblogs.com/agentgamer/p/6241302.html