返回

LeetCode 303:区域和检索——数组不可变

前端

问题

LeetCode 303:区域和检索——数组不可变 给定一个整数数组 nums ,求出数组从索引 i 到 j(i ≤ j)范围内元素的总和,包含 i、j 两点。

示例 1:

输入:nums = [-2, 0, 3, -5, 2, -1]i = 0,j = 2
输出:1
解释:求出nums[0] + nums[1] + nums[2] = (-2) + 0 + 3 = 1

示例 2:

输入:nums = [-2, 0, 3, -5, 2, -1],i = 2,j = 5
输出:-1
解释:求出nums[2] + nums[3] + nums[4] + nums[5] = 3 + (-5) + 2 + (-1) = -1

解题思路

暴力求解法

最直接的解法是暴力求解,每次查询时,直接累加从索引 i 到 j 之间的元素值。这种方法的时间复杂度为 O(n),其中 n 是数组 nums 的长度。

def range_sum(nums, i, j):
    sum = 0
    for k in range(i, j + 1):
        sum += nums[k]
    return sum

前缀和优化

为了优化暴力求解法的效率,我们可以使用前缀和优化技术。前缀和数组 preSum[i]存储着从索引 0 到 i 的元素和,因此,我们可以通过以下公式计算从索引 i 到 j 的元素和:

sum(i, j) = preSum[j] - preSum[i - 1]

前缀和数组可以一次性预处理得到,时间复杂度为 O(n),之后每次查询的时间复杂度仅为 O(1)。

def range_sum(nums):
    n = len(nums)
    preSum = [0] * (n + 1)
    for i in range(n):
        preSum[i + 1] = preSum[i] + nums[i]

    def range_sum_helper(i, j):
        return preSum[j + 1] - preSum[i]

    return range_sum_helper

nums = [-2, 0, 3, -5, 2, -1]
range_sum = range_sum(nums)
print(range_sum(0, 2))  # 1
print(range_sum(2, 5))  # -1

动态规划

这个问题也可以使用动态规划来解决。我们定义状态 dp[i][j] 为从索引 i 到 j 的元素和。状态 dp[i][j] 可以由以下公式计算得到:

dp[i][j] = dp[i - 1][j] + nums[i]

边界条件是 dp[i][i] = nums[i]。

def range_sum(nums):
    n = len(nums)
    dp = [[0] * n for _ in range(n)]
    for i in range(n):
        dp[i][i] = nums[i]

    for i in range(n - 1, -1, -1):
        for j in range(i + 1, n):
            dp[i][j] = dp[i - 1][j] + nums[i]

    def range_sum_helper(i, j):
        return dp[i][j]

    return range_sum_helper

nums = [-2, 0, 3, -5, 2, -1]
range_sum = range_sum(nums)
print(range_sum(0, 2))  # 1
print(range_sum(2, 5))  # -1

总结

LeetCode 303:区域和检索——数组不可变 是一个经典的问题,有多种解法思路。暴力求解法的时间复杂度为 O(n),前缀和优化的时间复杂度为 O(1),动态规划的时间复杂度也为 O(1)。在实际应用中,我们可以根据具体情况选择合适的解法。