前缀和是实现数组区间和的一种方法,其原理在于预先将一个数组的起始位置到数组任意位置的数值和存入另一个新的数组中,这个新的数组就叫前缀和数组。通过这种方法可以快速查询数组一段区间的和,适用于需要频繁查询数组某段区间和的场景。其主要思想是以空间换时间。需要注意的是该前缀指的是数组的下标,且求数组前缀和分为一维和二维的。代码如下:
一维:
func PrefixSumOne(arr []int, start, end int) int {
if start < 0 {
return -1
}
arrSum := make([]int, len(arr))
for i, v := range arr {
if i == 0 {
continue
}
arrSum[i] = arrSum[i-1] + v
}
return arrSum[end] - arrSum[start] + arr[start]
}
其步骤为:1.判定边界条件2.创建一个和原数组一样大的前缀数组。
3.通过“当前前缀和等于前一个前缀和加上原数组当前前缀的数值”依次填满前缀数组。
4.求原数组某个区间数值和“arrSum[end] - arrSum[start-1] ”但是上面代码考虑到当起始为0时,start-1越界,所以采用“arrSum[end] - arrSum[start] + arr[start]”(同时也减少了一次赋值)
而二维数组的思想与一维相同,代码如下:
func PrefixSumTwo(arr [][]int, rowStart, rowEnd, columnStart, columnEnd int) int {
rowStart = rowStart - 1
columnStart = columnStart - 1
if rowStart < -1 || columnStart < -1 || columnStart > columnEnd || rowStart > rowEnd || columnEnd > len(arr[0])-1 || rowEnd > len(arr)-1 {
return -1
}
arrSum := make([][]int, len(arr))
for i := range arr {
arrSum[i] = make([]int, len(arr[i]))
}
//第一行的前缀和
for j := 0; j < len(arr[0]); j++ {
if j == 0 {
arrSum[0][j] = arr[0][j]
} else {
arrSum[0][j] = arrSum[0][j-1] + arr[0][j]
}
}
//第一列的前缀和
for i := 1; i < len(arr); i++ {
arrSum[i][0] = arrSum[i-1][0] + arr[i][0]
}
for i := 1; i < len(arr); i++ {
for j := 1; j < len(arr[i]); j++ {
arrSum[i][j] = arrSum[i-1][j] + arrSum[i][j-1] - arrSum[i-1][j-1] + arr[i][j]
}
}
fmt.Println(arrSum)
prefixSum := arrSum[rowEnd][columnEnd]
if rowStart == -1 && columnStart != -1 {
prefixSum = prefixSum - arrSum[rowEnd][columnStart]
}
if columnStart == -1 && rowStart != -1 {
prefixSum -= arrSum[rowStart][columnEnd]
}
if columnStart != -1 && rowStart != -1 {
prefixSum = prefixSum - arrSum[rowStart][columnEnd] - arrSum[rowEnd][columnStart] + arrSum[rowStart][columnStart]
}
return prefixSum
}
只是二维数组的边界判定条件更为复杂,并且步骤三有所不同,其核心代码为
arrSum[i][j] = arrSum[i-1][j] + arrSum[i][j-1] - arrSum[i-1][j-1] + arr[i][j]
下面用形象的图像表示:
求红色区域 其面积=整个面积-两个长方形面积+重叠的正方形面积