LeetCode 307. 区域和检索 - 数组可修改

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

题目描述
给定一个整数数组  nums,求出数组从索引 i 到 j  (i ≤ j) 范围内元素的总和,包含 i,  j 两点。

update(i, val) 函数可以通过将下标为 i 的数值更新为 val,从而对数列进行修改。

示例:

Given nums = [1, 3, 5]

sumRange(0, 2) -> 9
update(1, 2)
sumRange(0, 2) -> 8
说明:

数组仅可以在 update 函数下进行修改。
你可以假设 update 函数与 sumRange 函数的调用次数是均匀分布的。

算法1
区间求和 自然使用 线段树 或者线段数组
这里以线段树为例
以 空间换时间 记录线段之间的和 最大最小值等
由于是树 即使其中一部分元素改变或者某一个元素改变 更改记录也只是log(n)的复杂度

class SegmentTreeNode {
public:
    SegmentTreeNode(int start,int end,int sum,
        SegmentTreeNode* left = nullptr,
        SegmentTreeNode* right = nullptr):
        start(start),
        end(end),
        sum(sum),
        left(left),
        right(right){}
    SegmentTreeNode(const SegmentTreeNode&) = delete;
    SegmentTreeNode& operator=(const SegmentTreeNode&) = delete;
    ~SegmentTreeNode() {
        delete left;
        delete right;
        left = right = nullptr;
    }

    int start;
    int  end;
    int sum;
    SegmentTreeNode* left;
    SegmentTreeNode* right;
};

class NumArray {
public:
    NumArray(vector<int> nums) {
        nums_.swap(nums);
        if (!nums_.empty())
            root_.reset(buildTree(0, nums_.size() - 1));
    }

    void update(int i, int val) {
        updateTree(root_.get(), i, val);
    }

    int sumRange(int i, int j) {
        return sumRange(root_.get(), i, j);
    }
private:
    vector<int> nums_;
    std::unique_ptr<SegmentTreeNode> root_;

    SegmentTreeNode* buildTree(int start, int end) {
        if (start == end) {
            return new SegmentTreeNode(start, end, nums_[start]);
        }
        int mid = start + (end - start) / 2;
        auto left = buildTree(start, mid);
        auto right = buildTree(mid + 1, end);
        auto node = new SegmentTreeNode(start, end, left->sum + right->sum,
            left, right);

        return node;
    }

    void updateTree(SegmentTreeNode* root, int i, int val) {
        if (root->start == i && root->end == i) {
            root->sum = val;
            return;
        }
        int mid = root->start + (root->end - root->start) / 2;
        if (i <= mid) {
            updateTree(root->left, i, val);
        }
        else {
            updateTree(root->right, i, val);
        }
        root->sum = root->left->sum + root->right->sum;
    }

    int sumRange(SegmentTreeNode* root, int i, int j) {
        if (i == root->start && j == root->end) {
            return root->sum;
        }
        int mid = root->start + (root->end - root->start) / 2;
        if (j <= mid) {
            return sumRange(root->left, i, j);
        }
        else if (i > mid) {
            return sumRange(root->right, i, j);
        }
        else {
            return sumRange(root->left, i, mid) + sumRange(root->right, mid + 1, j);
        }
    }
};

原文地址:https://www.cnblogs.com/itdef/p/11968069.html

时间: 2024-10-13 12:03:49

LeetCode 307. 区域和检索 - 数组可修改的相关文章

307.区域与检索--数组可修改

区域与检索--数组可修改 线段树 参考 链接 代码 class NumArray { private ArrayList<Integer> sumSegmentTree; private int n; public NumArray(int[] nums) { n = nums.length; sumSegmentTree = new ArrayList<>(2 * n + 1); for (int i = 0; i < n; i++) { sumSegmentTree.ad

[Leetcode] 第307题 区域和检索-数组可修改

参考博客:(LeetCode 307) Range Sum Query - Mutable(Segment Tree) 一.题目描述 给定一个整数数组  nums,求出数组从索引 i 到 j  (i ≤ j) 范围内元素的总和,包含 i,  j 两点. update(i, val) 函数可以通过将下标为 i 的数值更新为 val,从而对数列进行修改. 示例: Given nums = [1, 3, 5] sumRange(0, 2) -> 9 update(1, 2) sumRange(0, 2

[Leetcode]303.区域和检索

题目 1.区域和检索: 简单题,前缀和方法 乍一看就觉得应该用前缀和来做,一个数组多次查询. 实现方法: 新建一个private数组prefix_sum[i],用来存储nums前i个数组的和, 需要找区间和的时候直接通过prefix_sum[j]-prefix[i-1]即可得到从[i,j]区间的和,当i是0的时候需要特殊处理以防数组越界. 1 class NumArray { 2 public: 3 NumArray(vector<int> nums) { 4 prefix_sum.reser

【leetcode 简单】 第七十九题 区域和检索 - 数组不可变

给定一个整数数组  nums,求出数组从索引 i 到 j  (i ≤ j) 范围内元素的总和,包含 i,  j 两点. 示例: 给定 nums = [-2, 0, 3, -5, 2, -1],求和函数为 sumRange() sumRange(0, 2) -> 1 sumRange(2, 5) -> -1 sumRange(0, 5) -> -3 说明: 你可以假设数组不可变. 会多次调用 sumRange 方法. class NumArray: def __init__(self, n

[LeetCode] Range Sum Query 2D - Mutable 二维区域和检索 - 可变

Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2). The above rectangle (with the red border) is defined by (row1, col1) = (2, 1) and (row2, co

线段树 数据结构的简介和 leetcode 307

之前一直听说线段树是一个很高级很难的数据结构,今天简单了解了下, 感觉就是二叉树加几个全局变量啊,原来这么easy?(开个玩笑) 简单说几个特点, 1. 每个节点除了存放left,right指针之外,还存着一个范围(这个范围一般是构建线段树之前数组的索引范围), 就是以当前节点为根的情况下,对自己下面所有节点的求交集, 还可以根据你的需求 加一些别的特殊字段,sum,max,min等等 2. 数据集都存在叶子节点上,非叶子节点只做归纳总结 一般还有几个操作 1. 初始化,就是把一个数组初始化成一

leetCode 118. Pascal&#39;s Triangle 数组 (杨辉三角)

118. Pascal's Triangle Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5,Return [      [1],     [1,1],    [1,2,1],   [1,3,3,1],  [1,4,6,4,1] ] 题目大意: 输入行数,输出如上图所示的数组.(杨辉三角) 思路: 用双vector来处理当前行和下一行. 代码如下: cla

树状数组 区间修改+区间查询

其实直到不久前都几乎不会用树状数组,请教了PPZ大佬之后终于懂了一点点. 然后小蒟蒻现在才知道了树状数组区间修改+区间查询的方法QAQ 传送门 Codevs 线段树练习3 //Twenty #include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<queu

【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询

题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作,每次为一下三种之一: RELEASE x:对x执行一次感染: RECENTER x:把根节点改为x,并对原来的根节点执行一次感染: REQUEST x:询问x子树中所有节点感染代价的平均值. 输入 输入的第一行包含两个整数n和m,分别代表局域网中计算机的数量,以及操作和询问的总数.接下来n-1行,