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
}