leetcode 307. Range Sum Query - Mutable【线段树】【medium】| 刷题打卡

417 阅读2分钟

一、题目描述:

leetcode 307. Range Sum Query - Mutable:给定一个数组nums和两种类型的查询,能在其中更新数组中索引的值,并检索数组中范围的和。

  • 实现NumArray类:NumArray(int[]nums)用整数数组nums初始化对象。
  • void update(int index,int val)将nums[index]的值更新为val。
  • int sumRange(int left,int right)返回子数组nums[left,right](即nums[left]+nums[left+1],…,nums[right])之和。

二、思路分析:

1.类别

线段树

2.做题思路

这题可以说是线段树的模板题,关于查找和线段树见第四点。

三、AC 代码:

void buildTree(int *tree, vector<int> &nums, int left, int right, int node)
{
    if (left == right)
        tree[node] = nums[left];
    else
    {
        int middle = (left + right) / 2;
        int left_node = 2 * node + 1;
        int right_node = 2 * node + 2;
        buildTree(tree, nums, left, middle, left_node);
        buildTree(tree, nums, middle + 1, right, right_node);
        tree[node] = tree[left_node]+tree[right_node];
    }
}

void updateTree(int i, int val, int left, int right, int node, int *tree)
{
    if (left == right)
    {
        tree[node] = val;
        return;
    }
    int left_node = 2 * node + 1;
    int right_node = 2 * node + 2;
    int middle = (left + right) / 2;
    if (i <= middle && i >= left) //注意边界条件
        updateTree(i, val, left, middle, left_node, tree);
    else //if(i>middle && i<=right)
        updateTree(i, val, middle + 1, right, right_node, tree);
    tree[node] = tree[left_node] + tree[right_node];
}

int searchTree(int L, int R, int left, int right, int node, int *tree)
{
    if (R < left || L > right)
        return 0;
    if (L <= left && R >= right)
        return tree[node];
    if (left == right)
        return tree[node];
    int middle = (left + right) / 2;
    int left_node = 2 * node + 1;
    int right_node = 2 * node + 2;
    int leftpart = searchTree(L, R, left, middle, left_node, tree);
    int rightpart = searchTree(L, R, middle + 1, right, right_node, tree);
    return leftpart + rightpart;
}

class NumArray
{
public:
    int tree[1000000];
    int length=0;
    NumArray(vector<int> &nums)
    {
        length = nums.size();
        if(length!=0)
        {
            buildTree(tree, nums, 0, length - 1, 0);
            for(int i=0;i<length;i++)
                update(i,nums[i]);
        }
    }

    void update(int i, int val)
    {
        updateTree(i, val, 0, length-1, 0, tree);
    }

    int sumRange(int i, int j)
    {
        int result = searchTree(i, j, 0, length-1, 0, tree);
        return result;
    }
};

四、总结

线段树

  • 在各个节点保存一条线段(数组中的一段子数组)
  • 用于高效解决连续区间的动态查询问题
  • 基本能保持每个操作的复杂度为O(logN)。

线段树用于查询区间,查找单个点有以下几种方法:

1.动态查找方法

  • 二叉排序树
  • 二叉平衡树

2.静态查找方法

  • 顺序查找

    • 时间复杂度: O(N)
  • 折半查找

    • 必须采用顺序存储,不能用于链表
    • 最坏情况 =平均情况=O(lgN)
    • 查找不成功时,最多需要比较的次数不超过树的深度 为lgN(向下取整)+1
  • 分块查找

    • 分子表,块间有序,块内无序,这时候块间进行索引查找,块内进行顺序查找。
    • O(lgN)和O(N)之间
  • 散列结构

    • 平均查找长度:每个关键字要查找的次数之和/关键字的个数

    • 每个余数相同的树取对应的数组元素里面找

    • 时间复杂度 O(1)


    本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情