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

算法先锋·半月创作挑战赛 10w+人浏览 46人参与

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子数组
0nums[0] = [2]2
1nums[0 … 1] = [2, 3]5
2nums[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完整代码如下:

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完整代码如下:

# -*-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)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

福大大架构师每日一题

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值