前缀和应用总结

36 篇文章 2 订阅
30 篇文章 0 订阅

前缀和是一个数组的某项下标之前(包括此项元素)的所有数组元素的和。 

1、一维前缀和

公式:sum[i] = sum[i-1] + a[i] 

根据上述表达式我们可以以O(1)求出区间[i,j]的区间和  :

 sum = [0]*(n+1)  # 一般+1为了边界计算方便 
 for i in range(1, n+1):
     sum[i] = sum[i-1] + nums[i-1]

题目:和为K的子数组

给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。

示例 1 :

输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。

来源:力扣(LeetCode)
链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

 def subarraySum(self, nums, k):
        if not nums:
            return 0
        n = len(nums)
        sum = 0   # 前缀和
        sum_dict = {0:1}  # 记录前缀和数量
        count = 0
        for i in range(n):
            sum += nums[i]
            if sum_dict.get(sum - k):
                count += sum_dict.get(sum - k)  # +前缀数量
            sum_dict[sum] = sum_dict.get(sum, 0) + 1

        return count

2、二维前缀和

公式:

sum[i][j]存储左上角坐标为(0,0),右下角坐标为(i,j)的子矩阵的和。

sum[i][j] = matrix[i - 1][j - 1] + \sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1]递推求值即可,两部分相加,减去重复计算部分。

value = sum[i][j] - sum[i - k][j] - \sum[i][j - k] + sum[i - k][j - k]可求得一个k * k大小子矩阵的和。

sum = [[0 for j in xrange(m + 1)] for i in xrange(n + 1)]
for i in xrange(1, n + 1):
    for j in xrange(1, m + 1):
        sum[i][j] = matrix[i - 1][j - 1] + sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1]

 题目1:滑动窗口矩阵的最大值

给定一个n * m矩阵数组和一个移动矩阵窗口(大小k * k),在每次迭代时将窗口从左上移到右下,在每次移动时找到窗口内的最大和。
如果答案不存在,则返回0。

来源:lintcode
链接:LintCode 炼码 - ChatGPT!更高效的学习体验!

def maxSlidingWindow2(self, matrix, k):
        n = len(matrix)
        if n == 0 or n < k:
            return 0
        m = len(matrix[0])
        if m == 0 or m < k:
            return 0
        sum = [[0 for j in xrange(m + 1)] for i in xrange(n + 1)]
        for i in xrange(1, n + 1):
            for j in xrange(1, m + 1):
                sum[i][j] = matrix[i - 1][j - 1] + sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1]
        max_value = -0x80000000
        for i in xrange(k, n + 1):
            for j in xrange(k, m + 1):
                value = sum[i][j] - sum[i - k][j] - sum[i][j - k] + sum[i - k][j - k]
                if value > max_value:
                    max_value = value

        return max_value

题目2:元素和为目标值的子矩阵数量

给出矩阵 matrix 和目标值 target,返回元素总和等于目标值的非空子矩阵的数量。

子矩阵 x1, y1, x2, y2 是满足 x1 <= x <= x2 且 y1 <= y <= y2 的所有单元 matrix[x][y] 的集合。

如果 (x1, y1, x2, y2) 和 (x1', y1', x2', y2') 两个子矩阵中部分坐标不同(如:x1 != x1'),那么这两个子矩阵也不同。

来源:力扣(LeetCode)
链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

与上一个题的区别:

  1. 窗口大小不确定,窗口大小k=1~m
  2. 窗口不是k*k的,有可能是长方形窗口

前缀和优化:

枚举上边界,处理子矩阵,转换成在一行内, 求一个数组连续子串和为target的问题了,也就是一维前缀和。

def numSubmatrixSumTarget(matrix, target):
    if not matrix or not matrix[0]:
        return None
    n, m = len(matrix), len(matrix[0])
    count = 0
    for start_row in range(n):
        arr = [0] * m   # 一行一行累积求和,用一维和代替二维和
        for i in range(start_row, n):
            sum_hash = {}  # 存储前缀和的数量
            sum = 0     # 前缀和
            for j in range(m):
                arr[j] += matrix[i][j]
                sum += arr[j]
                if sum == target:  # 整个矩阵和等于目标值
                    count += 1
                if sum - target in sum_hash:  # 子矩阵和等于目标值
                    count += sum_hash[sum - target]
                sum_hash[sum] = sum_hash.get(sum, 0) + 1
    return count

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值