首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >2025-07-30:变长子数组求和。用go语言,给定一个长度为 n 的整数数组 nums。对于数组中的每个位置 i(范围是 0

2025-07-30:变长子数组求和。用go语言,给定一个长度为 n 的整数数组 nums。对于数组中的每个位置 i(范围是 0

作者头像
福大大架构师每日一题
发布2025-08-05 15:07:15
发布2025-08-05 15:07:15
18200
代码可运行
举报
运行总次数:0
代码可运行

2025-07-30:变长子数组求和。用go语言,给定一个长度为 n 的整数数组 nums。对于数组中的每个位置 i(范围是 0 到 n-1),我们定义一个子数组,区间为 nums[start ... i],其中 start 等于 max(0, i - nums[i])。

任务是计算并返回对于每个位置 i,所对应的子数组内所有元素的累加和。

简而言之,就是对于每个元素,根据它的值确定子数组的起始位置,然后求该子数组的元素和。

1 <= n == nums.length <= 100。

1 <= nums[i] <= 1000。

输入:nums = [2,3,1]。

输出:11。

解释:

下标 i

子数组

0

nums[0] = [2]

2

1

nums[0 ... 1] = [2, 3]

5

2

nums[1 ... 2] = [3, 1]

4

总和

11

总和为 11 。因此,输出 11 。

题目来自力扣3427。


代码实现的步骤(详细分解)

1. 初始化辅助数组 diff

  • • 定义一个长度为 len(nums) + 1 的整数数组 diff,初始时全部为0。
  • • 这个数组的作用是用作差分数组,表示某个范围内的子数组计数的增减情况。

2. 遍历 nums,使用差分数组来标记每个子数组的起止范围

nums 中每个元素 nums[i]

  • • 计算起始位置 start = max(0, i - nums[i])
  • diff[start]++:表示从位置 start 开始,有一个新的子数组加进来
  • diff[i+1]--:表示从位置 i+1 开始,前面的那个子数组不再计入(因为子数组截止到 i)

换句话说,用差分数组标记了每个子数组所覆盖的区间。

3. 计算累计的子数组出现次数(即在每个位置上的“活跃”子数组数量)

定义变量 sd = 0,它表示当前索引 i 处子数组的数量。

遍历数组索引 i:

  • sd += diff[i] :通过累加差分,得到当前位置 i 被多少个子数组覆盖(“活跃”的子数组个数)

4. 计算每个位置元素对总和的贡献

  • • 对于每个位置 i,对应的元素为 nums[i],它出现于 sd 个子数组里。
  • • 所以 nums[i] 的总加和值贡献就是 nums[i] * sd

将这些贡献累加到变量 ans 中。

5. 返回最后的累加和 ans


总体流程总结

  • • 利用差分数组来高效标记每个子数组的起止范围
  • • 遍历差分数组累加,得到每个位置被子数组覆盖的计数
  • • 乘以对应元素的值,累计求和
  • • 返回计算结果

这种做法避免了重复计算每个子数组内元素,从而提高效率。


时间复杂度分析

  • • 第一次循环(遍历 nums):O(n)
  • • 第二次循环(遍历 nums 计算答案):O(n)
  • • 总体时间复杂度:O(n),其中 n 是数组长度

空间复杂度分析

  • • 额外使用了一个长度为 n+1 的差分数组 diff
  • • 空间复杂度为 O(n)

总结:

  • 时间复杂度: O(n)
  • 空间复杂度: O(n)

该算法利用差分数组技巧,从而避免了嵌套循环的暴力求和(O(n^2)),效率较高。

Go完整代码如下:

.

代码语言:javascript
代码运行次数:0
运行
复制
package main

import (
    "fmt"
)

func subarraySum(nums []int) (ans int) {
    diff := make([]int, len(nums)+1)
    for i, num := range nums {
        diff[max(i-num, 0)]++
        diff[i+1]--
    }

    sd := 0
    for i, x := range nums {
        sd += diff[i]
        ans += x * sd
    }
    return
}

func main() {
    nums := []int{2, 3, 1}
    result := subarraySum(nums)
    fmt.Println(result)
}

Python完整代码如下:

.

代码语言:javascript
代码运行次数:0
运行
复制
# -*-coding:utf-8-*-

def subarray_sum(nums):
    n = len(nums)
    diff = [0] * (n + 1)
    for i, num in enumerate(nums):
        start = max(i - num, 0)
        diff[start] += 1
        diff[i + 1] -= 1

    ans = 0
    sd = 0
    for i, x in enumerate(nums):
        sd += diff[i]
        ans += x * sd
    return ans

if __name__ == "__main__":
    nums = [2, 3, 1]
    result = subarray_sum(nums)
    print(result)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-07-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 福大大架构师每日一题 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 代码实现的步骤(详细分解)
    • 1. 初始化辅助数组 diff
    • 2. 遍历 nums,使用差分数组来标记每个子数组的起止范围
    • 3. 计算累计的子数组出现次数(即在每个位置上的“活跃”子数组数量)
    • 4. 计算每个位置元素对总和的贡献
    • 5. 返回最后的累加和 ans
  • 总体流程总结
  • 时间复杂度分析
  • 空间复杂度分析
  • Go完整代码如下:
  • Python完整代码如下:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档