303. 区域和检索-数组不可变

题目描述:

给定一个整数数组  nums,处理以下类型的多个查询:

计算索引 left 和 right (包含 left 和 right)之间的 nums 元素的 和 ,其中 left <= right

实现 NumArray 类:

  • NumArray(int[] nums) 使用数组 nums 初始化对象

  • int sumRange(int i, int j) 返回数组 nums 中索引 left 和 right 之间的元素的 总和 ,包含 left 和 right 两点(也就是 nums[left] + nums[left + 1] + … + nums[right] )

测试用例:

示例 1:

输入:
["NumArray", "sumRange", "sumRange", "sumRange"]
[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]
输出:
[null, 1, -1, -3]
解释:
NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]);
numArray.sumRange(0, 2); // return 1 ((-2) + 0 + 3)
numArray.sumRange(2, 5); // return -1 (3 + (-5) + 2 + (-1))
numArray.sumRange(0, 5); // return -3 ((-2) + 0 + 3 + (-5) + 2 + (-1))

限制及提示:

  • 1 <= nums.length <= 10^4
  • -10^5 <= nums[i] <= 10^5
  • 0 <= i <= j < nums.length
  • 最多调用 10^4 次 sumRange 方法

解题分析及思路:

方法一:二叉索引树

该题直接用暴力每次计算left到right之间值的和即可,但是也可以使用树状数组来进行解答。

首先建立一棵二叉索引树。

func Constructor(nums []int) NumArray {
	l := len(nums)
	ints := make([]int, l+1)
	for index := 1; index <= l; index++ {
		index1 := index
		for index1 <= l {
			ints[index1] += nums[index-1]
			index1 += lowBit(index1)
		}
	}
	return NumArray{
		ints,
	}
}

然后每次计算的两个区间的值的时候,计算sum(right + 1) - sum(left)即可。

func sum(ints []int, index int) (ans int) {
	for index > 0 {
		ans += ints[index]
		index -= lowBit(index)
	}
	return ans
}

复杂度:

  • 时间复杂度:
    • 初始化O(logN)
    • 检索O(1)
  • 空间复杂度:O(N)

执行结果:

  • 执行用时:24 ms, 在所有 Go 提交中击败了82.00%的用户
  • 内存消耗:9.8 MB, 在所有 Go 提交中击败了21.91%的用户

方法二:前缀和

对于计算[left,right]区间的和,我们可以理解为[0,right]区间的和减去[0,left-1]区间的和。

所以可以通过前缀和的方式进行解答:

  • 首先,我们可以用一个数组 sums 记录数组 nums 的前缀和.
  • 然后,对于检索操作,我们可以通过 sums[right] - sums[left-1] 得到区间和。

只需注意:

  • 初始化sums时,首先需要对nums[0]进行初始化。
  • 检索时,需要判断left是否为0,如果是0,则直接返回sums[right],因为 0 - 1会越界。
type NumArray struct {
	sums []int
}

func Constructor(nums []int) NumArray {
	var sums = []int{
		nums[0],
	}
	for i := 1; i < len(nums); i++ {
		sums = append(sums, sums[i-1]+nums[i])
	}
	return NumArray{sums: sums}
}

func (this *NumArray) SumRange(left int, right int) int {
	if left == 0 {
		return this.sums[right]
	}
	return this.sums[right] - this.sums[left-1]
}

复杂度:

  • 时间复杂度:
    • 初始化O(N)
    • 检索O(1)
  • 空间复杂度:O(N)

执行结果:

  • 执行用时:21 ms, 在所有 Go 提交中击败了60.07%的用户
  • 内存消耗:9.03 MB, 在所有 Go 提交中击败了97.03%的用户

通过次数 268.8K 提交次数 342.9K 通过率 78.4%

Related Posts

100. 相同的树

## 题目描述:给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。示例 1: 输入:p = [1,2,3], q = [1,2,3] 输出:true示例 2: ![](/img/leetco

read more

101. 对称二叉树

## 题目描述:给你一个二叉树的根节点 root , 检查它是否轴对称。示例 1: 输入:root = [1,2,2,3,4,4,3] 输出:true示例 2: ![](/img/leetcode/101对称二叉树/1698027008-nP

read more

104. 二叉树的最大深度

## 题目描述: 给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。说明: 叶子节点是指没有子节点的节点。**测试用例:**示例1: 输入:root = [3,9,20,null,null,15,7] 输出:3 3 / \ 9 20 / \ 15 7 示例2: ``` 输入:roo

read more

108. 将有序数组转换为二叉搜索树

## 题目描述:给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。示例 1: ``` 输入:nums = [-10,-3,0,5,9] 输出:

read more

118. 杨辉三角

## 题目描述:给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。在「杨辉三角」中,每个数是它左上方和右上方的数的和。 示例 1: ``` 输入: numRows = 5 输出: [[1],[1,1],[1,

read more

1200. 最小绝对差

## 题目描述: 给你个整数数组 arr,其中每个元素都 不相同。请你找到所有具有最小绝对差的元素对,并且按升序的顺序返回。**测试用例:**示例 1: 输入:arr = [4,2,1,3] 输出:[[1,2],[2,3],[3,4]]示例 2: 输入:arr = [1,3,6,10,15] 输出:[[1,3]]示例 3: ``` 输入

read more