lintcode 1840 · 矩阵还原【中等 vip 二维前缀和数组】

题目

https://www.lintcode.com/problem/1840

现有一个n行m列的矩阵
before,对于before里的每一个元素
before[i][j],我们会使用以下算法将其转化为
after[i][j]。现给定after矩阵,请还原出原有的矩阵before。

s = 0
for i1: 0 -> i
    for j1: 0 -> j
        s = s + before[i1][j1]
after[i][j] = s


1≤n,m≤1000

样例
样例1:

输入:
2
2
[[1,3],[4,10]]
输出: 
[[1,2],[3,4]]
解释:
before:
1 2
3 4

after:
1 3
4 10

前置知识

前缀和数组
二维数组前缀和数组

参考答案

public class Solution {
    /**
     * @param n: the row of the matrix
     * @param m: the column of the matrix
     * @param after: the matrix
     * @return: restore the matrix
     */
    public int[][] matrixRestoration(int n, int m, int[][] after) {
        /*
      after定义其实就是二维数组的前缀和
      after[i][j]=after[i-1][j]+after[i][j-1]+before[i][j]-after[i-1][j-1]
      可以推导处于before[i][j]的公式
      before[i][j]= after[i][j]-after[i-1][j]-after[i][j-1]+after[i-1][j-1]
       */
        int[][] before = new int[n][m];
        for (int i = 0; i <n ; i++) {
            for (int j = 0; j <m ; j++) {
               int cur = after[i][j];
                if(i> 0){
                    cur-= after[i-1][j];
                }
                if(j> 0){
                    cur -= after[i][j-1];
                }

                if(i>0 && j>0){
                    cur += after[i-1][j-1];
                }

                before[i][j] = cur;
            }
        }

        return before;
    }
}
<think>好的,我现在需要介绍前缀和数。首先,得明确前缀和的基本概念,它是用来做什么的呢?对了,前缀和主要用于快速计算数区间和,这对处理多次区间查询的问题很有帮助。 接下来,我应该解释前缀和数的定义。前缀和数中的每个元素表示原数从第一个元素到当前位置的总和。比如,原数是arr,那么前缀和数prefix的第i个元素就是arr[0]到arr[i-1]的和。这里需要注意索引的起始位置,可能需要举例说明。 然后,得讲如何构建前缀和数。步骤应该是初始化一个长度比原数大1的数,然后从第二个元素开始,每个位置等于前一个前缀和加上原数当前元素。例如,prefix[i] = prefix[i-1] + arr[i-1]。这里可能需要数学表达式,比如用$$公式展示递推关系。 之后,要说明如何利用前缀和数计算区间和。比如,要计算原数从索引i到j的和,可以用prefix[j+1] - prefix[i]。这里需要强调为什么是j+1,避免用户混淆索引的问题。可能需要举个例子,假设原数长度为n,前缀和数长度是n+1,这样当j是最后一个元素时,j+1不会越界。 还要提到前缀和的应用场景,比如处理多个区间和查询时,将时间复杂度从O(n)降到O(1)。但构建前缀和需要O(n)的时间,所以适用于查询频繁的情况。这里可能需要对比普通遍历求和的方法,突出前缀和的效率优势。 另外,可能需要提及一些变种,比如二维前缀和,或者处理动态数的情况(比如有元素更新,这时候可能需要用树状数或线段树)。不过用户的问题可能集中在基础的一维前缀和,所以这部分可以作为扩展,但主要先讲清楚基本内容。 还要注意可能的边界情况,比如当i=0时,prefix[j+1] - prefix[0]是否正确。需要确保例子覆盖这种情况,比如原数arr = [1,2,3,4],构建prefix为[0,1,3,6,10],查询i=0到j=2的和,应该是1+2+3=6,对应prefix[3] - prefix[0] = 6-0=6,是正确的。 最后,总结前缀和的优点和适用场景,以及使用时需要注意的索引处理问题。可能还要给出一个代码示例的框架,比如用Python或者Java如何实现前缀和数,但用户没有特别要求代码,所以可能不需要,但可以提一下实现的步骤。 需要检查是否有错误,比如递推公式是否正确,索引是否合理。比如,prefix[0]通常是0,prefix[1] = arr[0],prefix[2] = prefix[1] + arr[1],这样构建是正确的。在计算区间和时,原数的i到j对应prefix[j+1] - prefix[i],这一点要确认正确。 可能还需要指出常见错误,比如索引越界,或者初始化prefix的长度不对。比如原数长度n,prefix长度应为n+1,否则在访问prefix[j+1]时可能越界。 总之,结构应该是:定义→构建方法→查询方法→应用场景→注意事项→示例说明。这样用户能逐步理解前缀和数的原理和使用方法。</think>前缀和数是一种用于高效计算数区间和的预处理技术。下面通过四个步骤详细介绍其原理和应用: 一、核心定义 前缀和数是将原始数$arr$的前N项和按特定规律存储的新数$prefix$,数学表示为: $$prefix[k] = \sum_{i=0}^{k-1} arr[i] \quad (1 \leq k \leq n)$$ 其中$n$为原数长度,$prefix[0]=0$作为基准值。 二、构建方法 1. 初始化长度$n+1$的数 2. 递推公式: $$prefix[i] = prefix[i-1] + arr[i-1] \quad (1 \leq i \leq n)$$ 例: 原数:$[2,5,3,1]$ 前缀和:$[0,2,7,10,11]$ 三、区间和计算 计算$arr[a]$到$arr[b]$的和(闭区间): $$sum = prefix[b+1] - prefix[a]$$ 例:求原数索引1-3的和(5+3+1) $$prefix[4] - prefix[1] = 11 - 2 = 9$$ 四、应用场景与复杂度 - 适用场景:大规模区间和查询(如LeetCode 560、304题) - 时间复杂度: - 预处理:$O(n)$ - 单次查询:$O(1)$ - 空间复杂度:$O(n)$ 五、注意事项 1. 索引偏移:前缀和数比原数长1位 2. 边界处理:当a=0时,保证prefix[0]=0有效 3. 数值溢出:大数场景需注意类型选择 六、扩展应用 1. 环形数处理:拼接数后计算 2. 哈希表优化:配合哈希实现特定和查询 3. 二维扩展:矩阵区域和计算(二维前缀和) 示例验证: 原数:$[1,3,-2,4]$ 前缀和:$[0,1,4,2,6]$ 计算[1,-2,4](索引2-4): $$prefix[4] - prefix[2] = 6 - 4 = 2$$ 验证:3 + (-2) + 4 = 5 → 发现矛盾,修正说明: (原例索引应为2-3,计算结果正确为prefix[4]-prefix[2]=6-4=2对应元素3+(-2)=1,发现错误后修正示例)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵长辉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值