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:

  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.

问题:给定一个固定长度的数组,可以更新元素的值,求给定子数组的元素和。求和与更新操作交替进行。

解决方案

方案1,每次求和,直接遍历子数组进行求和。每次更新,直接根据下标更新元素值。求和操作时间复杂度为 O(n), 更新操作时间复杂度为O(1)

方案2,采用线段树存储原数组以及中间结果。

例子:输入数组{1, 3, 5, 7, 9, 11} 对应的线段树数据结构如下,叶子节点存储输入数组的元素,非叶子节点存储一个区域的和。

线段树是一个 full binary tree,可以用数组来存储。数组下标和线段树的节点之间的关系如下:

对于节点 i,

  • 其左子节点下标为 i*2+1
  • 其右节点下标为 i*2+2
  • 其父亲节点下标为 (i-1)/2

基于数组的线段树表示例子如下:

求和思路:计算子数组[l, r] 的和时,对于给定节点 node 有:

  • 如果节点 node 代表的范围在 [l, r] 之内,则返回节点 node 的值
  • 如果节点 node 代表的范围完全不在 [l, r] 之内,则返回 0
  • 其他情况,节点 node 代表的范围一部分在 [l, r]之内,一部分不在之内,则对于节点 node 的左右子节点分别应用该规则进行处理。

更新思路:根据给定的下标,更新下标对应元素在线段树的叶子节点,并更新从该叶子节点到根节点路径上的所有祖先节点。

构建线段树:根据输入数组,求得线段树需要的节点值。例如 {1, 3, 5, 7, 9, 11, 4, 12, 20, 16, 36}

对节点值进行反序处理,则得到基于数组结构的线段树。例如 {36, 16, 20, 12, 4, 11, 9, 7, 5, 3, 1}

代码实现如下:

#include <vector>
using namespace std;struct TreeNode{
int val;
pair<int, int> idxRange; TreeNode(int val, int lRange, int rRange){
this->val = val;
this->idxRange = make_pair(lRange, rRange);
}
}; class NumArray { vector<int> nums;
vector<TreeNode *> nodesVec;
vector<TreeNode *> treeVec; /**
* calculate the nodes of the segment tree based on the input values in nums
*/
void calculateNodes(){
for(int i=; i < nums.size(); i++){
TreeNode *tn = new TreeNode(nums[i], i, i);
this->nodesVec.push_back(tn);
} for(int i =; i + < nodesVec.size(); i+=){
int val = nodesVec[i]->val + nodesVec[i+]->val;
int l = min(nodesVec[i]->idxRange.first, nodesVec[i+]->idxRange.first);
int r = max(nodesVec[i]->idxRange.second, nodesVec[i+]->idxRange.second);
TreeNode *tn = new TreeNode(val, l, r);
nodesVec.push_back(tn);
}
} /**
* build segment tree base on Vector.
* For node i,
* the left child index: i * 2 + 1
* the right child index: i * 2 + 2
* the parent index: (i - 1)/2
*/
void buildVectorBasedSegmentTree(){
for(int i=nodesVec.size() - ; i >= ; i--){
treeVec.push_back(nodesVec[i]);
}
} public:
NumArray(){}
virtual ~NumArray(){} /**
* initialization
*/
NumArray(vector<int> nums){
this->nums = nums;
calculateNodes();
buildVectorBasedSegmentTree();
} /**
* update the value of the node in the index i in treeVec
*/
void update(int i, int val){
int leafIdx = treeVec.size() - ( + i );
int diff = val - treeVec[leafIdx]->val;
updateNodes(leafIdx, diff);
} /**
* update the value of nodes in interval tree(segment tree) with the diff recursively.
*/
void updateNodes(int idx, int diff){
treeVec[idx]->val += diff;
if(idx > ){
idx = (idx -) / ;
updateNodes(idx, diff);
}
} int sumRange(int i, int j){
return getSum(, i, j);
} /**
* check the node in i-th index in treeVec, to calculate the sum of leaf
*/
int getSum(int nodeIdx, int rangeL, int rangeR){
TreeNode* node = treeVec[nodeIdx];
if (rangeL <= node->idxRange.first && node->idxRange.second <= rangeR){
return node->val;
} if (node->idxRange.second < rangeL || rangeR < node->idxRange.first){
return ;
}
int nodeIdxL = nodeIdx * + ;
int nodeIdxR = nodeIdx * + ;
return getSum(nodeIdxL, rangeL, rangeR) + getSum(nodeIdxR, rangeL, rangeR);
}
};

Reference:

Segment Tree | Set 1 (Sum of given range), geeksforgeeks

Segment tree, wikipedia

[LeetCode] 307. Range Sum Query - Mutable 解题思路的更多相关文章

  1. [LeetCode] 307. Range Sum Query - Mutable 区域和检索 - 可变

    Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive ...

  2. leetcode@ [307] Range Sum Query - Mutable / 线段树模板

    Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive ...

  3. LeetCode - 307. Range Sum Query - Mutable

    Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive ...

  4. leetcode 307. Range Sum Query - Mutable(树状数组)

    Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive ...

  5. 【刷题-LeetCode】307. Range Sum Query - Mutable

    Range Sum Query - Mutable Given an integer array nums, find the sum of the elements between indices ...

  6. [Leetcode Week16]Range Sum Query - Mutable

    Range Sum Query - Mutable 题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/range-sum-query-mutable/de ...

  7. 【leetcode】307. Range Sum Query - Mutable

    题目如下: 解题思路:就三个字-线段树.这个题目是线段树用法最经典的场景. 代码如下: class NumArray(object): def __init__(self, nums): " ...

  8. 307. Range Sum Query - Mutable

    题目: Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclu ...

  9. leetcode 307 Range Sum Query

    问题描述:给定一序列,求任意区间(i, j)的元素和:修改任意一元素,实现快速更新 树状数组 树状数组的主要特点是生成一棵树,树的高度为logN.每一层的高度为k,分布在这一层的序列元素索引的二进制表 ...

随机推荐

  1. 华硕200系主板完美兼容M.2安装Win7系统

    虽然Windows 10系统的装机率正不断攀升,但经典的Windows 7依然有着大量的用户群体.特别是在我们中国, Windows 7依然是许许多多电脑用户的装机首选系统. 经久不衰的Windows ...

  2. 关于解决JetBrains 激活问题

    今天升级了下JetBrains 的一系列产品,安装后打开发现以前的激活失效了. 在网上看到网友们各类屏蔽和寻找服务器,尝试了下都不太方便. 最后去rover的个人博客看了下,很给力,总能跟上JetBr ...

  3. tidb集群某个节点报错之:node_exporter-9100.service failed

    今天启动集群tidb时出现一个错误,是某个tikv节点报错:node_exporter-9100.service  failed 一个节点的问题会导致整个集群启动失败.去此节点下的日志文件中查找,发现 ...

  4. 【2017下集美大学软工1412班_助教博客】团队作业9——事后分析(Beta版本)成绩公示

    作业要求 团队作业9 团队评分结果 编号 Total 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 2 ...

  5. python中的轻量级定时任务调度库:schedule

    提到定时任务调度的时候,相信很多人会想到芹菜celery,要么就写个脚本塞到crontab中.不过,一个小的定时脚本,要用celery的话太“重”了.所以,我找到了一个轻量级的定时任务调度的库:sch ...

  6. Ajax进阶

    "POST":请求 POST请求:(一共三个方法)<!DOCTYPE html><html lang="en"><head> ...

  7. cpu的组成及分工

    控制单元是上帝:掌控一切: 运算单元只负责算术和逻辑运算,运算的指令由控制单元提供,数据由寄存器提供: 存储单元:一方面给运算单元提供输入输出,另一方面在控制单元的控制下和内存通信: 控制单元使用运算 ...

  8. css权重 vs 浏览器渲染 -- css之弊病

    昨日,突现一个bug,令人十分恼火. 基本场景 自己实现一多选日历,可多选多天(相连或不相连均可)."贵司"的需求真心有些小复杂了,"市面"上没有这样的相似的东 ...

  9. data函数参数

    date(format,timestamp); 参数 描述 format 必需.规定输出日期字符串的格式.可使用下列字符: d - 一个月中的第几天(从 01 到 31) D - 星期几的文本表示(用 ...

  10. go标准库的学习-net

    参考:https://studygolang.com/pkgdoc 导入方式: import "net" net包提供了可移植的网络I/O接口,包括TCP/IP.UDP.域名解析和 ...