Leetcode-前缀和

Leetcode-前缀和



q238 除自身以外数组的乘积


题目传送门


题解

这道题我的第一反应就是需要用到两个数组,分别是顺序的前缀和数组以及逆序的前缀和数组,以1 2 3 4 (24 12 8 6)来举例,所谓的顺序前缀和数组就是nums1: 1 2 6 24,而逆序前缀和数组就是nums2: 24 24 12 4,构建好两个前缀和数组以后,开始构建res数组,res[i] = nums1[i - 1] * nums2[i + 1],然后处理一下首尾,res[0] = nums1[1], res[n - 1] = nums2[n - 2].
要求空间复杂度为常数,但是res数组不算在里面,所以一开始我把res数组构建成了逆序的前缀和数组.

func productExceptSelf(nums []int) []int {
	if len(nums) == 2 {
		return []int{nums[1], nums[0]}
	}
	res := make([]int, len(nums))
	// 将res数组构建成从右到左的前缀和数组
	res[len(res) - 1] = nums[len(nums) - 1]
	for i := len(res) - 2; i >= 0; i-- {
		res[i] = nums[i] * res[i + 1]
	}
	// 将nums数组构建成从左到右的前缀和数组
	for i := 1; i < len(nums); i++{
		nums[i] = nums[i] * nums[i - 1]
	}
	// 第一个元素实际上就是顺序前缀和数组的第二个元素
	res[0] = res[1]
	// 备份res数组的最后一个元素
	end := res[len(res) - 1]
	// 最后一个元素实际上就是逆序前缀和数组的倒数第二个元素
	res[len(res) - 1] = nums[len(nums) - 2]
	for i := 1; i <= len(res) - 2; i++ {
		if i != len(res) - 2 {
			res[i] = nums[i - 1] * res[i + 1]
		} else {
			res[i] = nums[i - 1] * end
		}
	}
	return res
}

其实官方题解的思想和我的是一样的,但是我的实现偏复杂了(没必要).我们可以从左往右遍历一次nums数组,用res[i]表示i之前所有元素的乘积,然后再从右往左遍历一次数组,把每个元素右边的所有值乘积都乘上一遍,用一个变量r来记录i之前的所有元素之积.

func productExceptSelf(nums []int) []int {
	res := make([]int, len(nums))
	res[0] = 1
	// res[i]表示i左边的所有数字相乘
	for i := 1; i < len(res); i++ {
		res[i] = res[i - 1] * nums[i - 1]
	}
	r := 1
	// r 表示i右边的所有数字相乘
	for i := len(res) - 1; i >= 0; i-- {
		res[i] = res[i] * r
		r *= nums[i]
	}
	return res
}

q560 和为k的子数组


题目传送门


题解

这道题可以使用暴力法来求解:

func subarraySum(nums []int, k int) int {
    count := 0
    for start := 0; start < len(nums); start++ {
        sum := 0
        for end := start; end >= 0; end-- {
            sum += nums[end]
            if sum == k {
                count++
            }
        }
    }
    return count
}

但是空间复杂度是O(n^2). 其实我们可以把前缀和保存在一个数组pre中,假设我们要在区间nums[i...j]中找和为k的子数组,其实就是找一个pre[i] - pre[j] = k的数,我们在遍历nums数组的过程中,pre[i]是已知的,k也是已知的,问题就转化成要找一个pre[j]满足pre[j] = pre[i],可以用一个map把前面出现过的所有前缀和都保存下来,那么pre数组其实可以是一个整数,因为pre只表示到当前下标i为止的前缀和,是不断更新的,在遍历的过程中判断:如果map[pre - k]不为0,就表示找到了pre[j],累加count即可.

func subarraySum(nums []int, k int) int {
	mp := make(map[int]int)
	mp[0] = 1
	pre, count := 0, 0
	for i := 0; i < len(nums); i++ {
		pre += nums[i]
		if _, ok := mp[pre-k]; ok {
			count += mp[pre-k]
		}
		mp[pre] += 1
	}
	return count
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值