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; } };