前缀和

一维前缀和

模版题

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
    "strings"
)

func main() {
    var reader = bufio.NewReader(os.Stdin)
    var x = readArray(reader)
    //var n, m = x[0], x[1]
    var nums = readArray(reader)
    var sums = make([]int, x[0]+1)
    for i := 0; i < x[0]; i++ {
        sums[i+1] = sums[i] + nums[i]
    }

    var cnt int
    var xx []int
    for cnt < x[1] {
        xx = readArray(reader)
        // 请注意题目下标是从1开始的
        fmt.Println(sums[xx[1]] - sums[xx[0]-1])
        cnt++
    }
}

func readLine(reader *bufio.Reader) string {
    var line, _ = reader.ReadString('\n')
    return strings.TrimRight(line, "\n")
}

func readInt(reader *bufio.Reader) int {
    var num, _ = strconv.Atoi(readLine(reader))
    return num
}

func readArray(reader *bufio.Reader) []int {
    var line = readLine(reader)
    var strList = strings.Split(line, " ")
    var nums = make([]int, 0)
    var err error
    var v int
    for i := 0; i < len(strList); i++ {
        if v, err = strconv.Atoi(strList[i]); err != nil {
            continue
        }
        nums = append(nums, v)
    }
    return nums
}

func nums2string(x []int, sep string) string {
    var b strings.Builder
    for i := 0; i < len(x); i++ {
        b.WriteString(strconv.Itoa(x[i]))
        b.WriteString(sep)
    }
    return b.String()
}

/*
输入一个长度为n的整数序列。

接下来再输入m个询问,每个询问输入一对l, r。

对于每个询问,输出原序列中从第l个数到第r个数的和。

输入格式
第一行包含两个整数n和m。

第二行包含n个整数,表示整数数列。

接下来m行,每行包含两个整数l和r,表示一个询问的区间范围。

输出格式
共m行,每行输出一个询问的结果。

数据范围
1≤l≤r≤n,
1≤n,m≤100000,
−1000≤数列中元素的值≤1000
输入样例:
5 3
2 1 3 6 4
1 2
1 3
2 4
输出样例:
3
6
10
*/

查找数组和

# 查找数组和
def search_sum(nums, lst):
    sums = [0] * (len(nums) + 1)
    # 查找前缀和
    for i in range(len(nums)):
        sums[i + 1] = sums[i] + nums[i]

    # 查找前缀和
    for left, right in lst:
        print(sums[right + 1] - sums[left])

if __name__ == '__main__':
    search_sum([1, 2, 3, 4, 5, 6], [(1, 3)])

和为K的子数组

Python3

# [和为K的子数组](https://leetcode-cn.com/problems/subarray-sum-equals-k/)
# 数据增强后O(N*N)已经过不了,Python版本
from typing import List
from collections import defaultdict


class Solution:
    # def subarraySum(self, nums: List[int], k: int) -> int:
    #     sums = [0] * (len(nums) + 1)
    #     # 求前缀和
    #     for i in range(len(nums)):
    #         sums[i + 1] = sums[i] + nums[i]
    #
    #     cnt = 0
    #     # 查找前缀和
    #     for i in range(len(sums) - 1):
    #         for j in range(i + 1, len(sums)):
    #             if sums[j] - sums[i] == k:
    #                 cnt += 1
    #     return cnt

    # 使用Map进行优化(只适用于统计次数而不关心具体的解) 时间复杂度O(N)
    def subarraySum(self, nums: List[int], k: int) -> int:
        dd = defaultdict(int)
        sums = 0
        dd[sums] = 1
        cnt = 0
        for num in nums:
            sums += num
            cnt += dd[sums - k]
            dd[sums] += 1
        return cnt

二维前缀和

imgimg

S[i,j]即为左图红框中所有数的的和为S[i,j]=S[i,j−1]+S[i−1,j]−S[i−1,j−1]+a[i,j] (x1,y1),(x2,y2)这一子矩阵中的所有数之和为S[x2,y2]−S[x1−1,y2]−S[x2,y1−1]+S[x1−1,y1−1]

模版题

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
    "strings"
)

func main() {
    var reader = bufio.NewReader(os.Stdin)
    var x = readArray(reader)
    var sums = make([][]int, x[0]+1)

    var nums = make([][]int, x[0])
    for i := 0; i < x[0]; i++ {
        nums[i] = readArray(reader)
    }

    for i := 0; i < x[0]+1; i++ {
        sums[i] = make([]int, x[1]+1)
    }
    for i := 0; i < x[0]; i++ {
        for j := 0; j < x[1]; j++ {
            sums[i+1][j+1] = sums[i+1][j] + sums[i][j+1] + nums[i][j] - sums[i][j]
        }
    }

    var cnt int
    var xx []int
    for cnt < x[2] {
        xx = readArray(reader)
        p(sums, xx)
        cnt++
    }
}

func p(sums [][]int, xx []int) {
    var a, b, c, d = xx[0], xx[1], xx[2], xx[3]
    // 建议画个图梳理关系 // https://www.acwing.com/solution/content/3797/
    fmt.Println(sums[c][d] + sums[a-1][b-1] - sums[a-1][d] - sums[c][b-1])
}

func readLine(reader *bufio.Reader) string {
    var line, _ = reader.ReadString('\n')
    return strings.TrimRight(line, "\n")
}

func readInt(reader *bufio.Reader) int {
    var num, _ = strconv.Atoi(readLine(reader))
    return num
}

func readArray(reader *bufio.Reader) []int {
    var line = readLine(reader)
    var strList = strings.Split(line, " ")
    var nums = make([]int, 0)
    var err error
    var v int
    for i := 0; i < len(strList); i++ {
        if v, err = strconv.Atoi(strList[i]); err != nil {
            continue
        }
        nums = append(nums, v)
    }
    return nums
}

func nums2string(x []int, sep string) string {
    var b strings.Builder
    for i := 0; i < len(x); i++ {
        b.WriteString(strconv.Itoa(x[i]))
        b.WriteString(sep)
    }
    return b.String()
}

/*
输入一个n行m列的整数矩阵,再输入q个询问,每个询问包含四个整数x1, y1, x2, y2,表示一个子矩阵的左上角坐标和右下角坐标。

对于每个询问输出子矩阵中所有数的和。

输入格式
第一行包含三个整数n,m,q。

接下来n行,每行包含m个整数,表示整数矩阵。

接下来q行,每行包含四个整数x1, y1, x2, y2,表示一组询问。

输出格式
共q行,每行输出一个询问的结果。

数据范围
1≤n,m≤1000,
1≤q≤200000,
1≤x1≤x2≤n ,
1≤y1≤y2≤m,
−1000≤矩阵内元素的值≤1000
输入样例:
3 4 3
1 7 2 4
3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4
输出样例:
17
27
21
*/

统计全为1的正方形子矩阵

Python3(超时)

# [统计全为1的正方形子矩阵](https://leetcode-cn.com/problems/count-square-submatrices-with-all-ones/)
from typing import List


class Solution:
    # 超时O(N^3)
    def countSquares(self, matrix: List[List[int]]) -> int:
        x = len(matrix)
        if x == 0:
            return 0
        y = len(matrix[0])
        if y == 0:
            return 0

        sums = [[0 for _ in range(y + 1)] for _ in range(x + 1)]
        # 构造前缀和
        for i in range(x):
            for j in range(y):
                sums[i + 1][j + 1] = sums[i + 1][j] + sums[i][j + 1] - sums[i][j] + matrix[i][j]

        cnt = 0
        # 查找前缀和
        # 扫描所有正方形
        # 边长
        for length in range(1, min(x, y) + 1):
            for i in range(0, x - length + 1):
                for j in range(0, y - length + 1):
                    cnt += sums[i + length][j + length] - sums[i][j + length] - sums[i + length][j] + sums[i][
                        j] == length * length

        return cnt

        # 这道题需要使用DP进行解答,这里只是一个使用二维前缀和解答的例子
        # 从时间复杂度看(数据范围是0--300), 对于O(N^3)则数据量级达27000000,Python版本可能会超时,使用go不会
        # go版本见同目录下的lc1277

Golang

package main

func countSquares(matrix [][]int) int {

    var (
        x int
        y int
        sums [][]int
        cnt int
    )
    x = len(matrix)
    if x == 0 {
        return 0
    }
    y = len(matrix[0])
    if y == 0 {
        return 0
    }
    // 初始化
    sums = make([][]int, x+1, x+1)
    for i := 0; i< x+1; i++ {
        sums[i] = make([]int, y+1, y+1)
    }
    // 填充前缀和
    for i :=0; i< x; i++ {
        for j:=0; j < y; j++ {
            sums[i+1][j+1] = sums[i+1][j] + sums[i][j+1] - sums[i][j] + matrix[i][j]
        }
    }

    // 查找前缀和
    // 扫描所有正方形
    // 边长
    var b = x
    if y < x {
        b = y
    }
    for length:=1 ;length< b+1; length ++ {
        for i:= 0; i<x-length+1; i++ {
            for j:=0; j < y-length+1; j++ {
                if sums[i + length][j + length] - sums[i][j + length] - sums[i + length][j] + sums[i][j] == length * length {
                    cnt++
                }
            }
        }
    }

    return cnt
}

最后更新于

这有帮助吗?