算法--差分

目录

1.一维差分

2.二维差分 

1.一维差分

  • 核心思想

差分简单来说就是相邻元素的差值。

  • 核心作用📍📍📍

对原数组 a 的一个区间 [l, r] 进行加 c 的操作,等价于对差分数组 d 的 d[l] 加 cd[r + 1] 减 c。通过这种方式,将对原数组区间的操作转化为对差分数组的单点操作,从而提高操作效率。(减法同理)

  • 核心代码

差分的实现步骤🌻

  1. 构造差分数组:遍历原数组,根据差分的定义计算差分数组的每个元素。
  2. 区间操作:对原数组的区间 [l, r] 进行加 c 的操作时,将差分数组的 d[l] 加 cd[r + 1] 减 c
  3. 还原原数组:通过差分数组还原原数组,即 a[i] = d[0] + d[1] +... + d[i],可以使用前缀和的方式计算。
//n是数组元素个数,m是操作个数, d数组为差分数组

//构造差分数组
for (int i = 1; i <= n; i++) {
     cin >> a[i];
     d[i] = a[i] - a[i - 1];
 }
//区间加减操作
 for (int i = 1; i <= m; i++) {
     int l, r, c;
     cin >> l >> r >> c;
     d[l] += c;
     d[r + 1] -= c;
 }
//切记:更新原始数组⚠️⚠️⚠️
 for (int i = 1; i <= n; i++) {
     a[i] = a[i - 1] + d[i];
     cout << a[i] << ' ';
 }

2.二维差分

  • 核心思想

二维差分的核心思想是通过记录二维数组中相邻元素的差值,将对原数组的子矩阵操作转化为对差分数组中对应元素的操作,以达到高效处理区间修改问题的目的

  • 核心作用📍📍📍

🌻具体来说,当需要对原二维数组中的某个子矩阵进行修改时,如对以\((x_1, y_1)\)为左上角、\((x_2, y_2)\)为右下角的子矩阵的每个元素都加上常数c,只需要在差分数组的四个关键位置\((x_1, y_1)\)、\((x_1, y_2 + 1)\)、\((x_2 + 1, y_1)\)、\((x_2 + 1, y_2 + 1)\)进行相应的加减操作即可。

图示:

  • 核心代码

2.1 构造二维差分数组

如果已知原二维数组 \(a_{i,j}\),可以通过如下方式构造差分数组 \(b_{i,j}\):

 
  • \(b_{i,j}=a_{i,j}-a_{i - 1,j}-a_{i,j - 1}+a_{i - 1,j - 1}\)

2.2 子矩阵修改

若要对原二维数组中以 \((x_1,y_1)\) 为左上角、\((x_2,y_2)\) 为右下角的子矩阵的每个元素都加上常数 c,只需对差分数组进行如下操作:

 
  • \(b_{x_1,y_1}+=c\)
  • \(b_{x_1,y_2 + 1}-=c\)
  • \(b_{x_2+1,y_1}-=c\)
  • \(b_{x_2 + 1,y_2+1}+=c\)

2.3 从差分数组还原原数组

可以通过对差分数组求二维前缀和来还原原数组,公式为:

 
  • \(a_{i,j}=a_{i - 1,j}+a_{i,j - 1}-a_{i - 1,j - 1}+b_{i,j}\)
//构造二维差分数组
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cin >> a[i][j];
            d[i][j] = a[i][j] - a[i][j - 1] - a[i - 1][j] + a[i - 1][j - 1];
        }
    }
//子矩阵加减操作
    for (int i = 0; i < q; i++) {
        int x1, y1, x2, y2, c;
        cin >> x1 >> y1 >> x2 >> y2 >> c;
        d[x1][y1] += c;
        d[x2 + 1][y1] -= c;
        d[x1][y2 + 1] -= c;
        d[x2 + 1][y2 + 1] += c;
    }
//切记:更新原二维数组⚠️⚠️⚠️
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + d[i][j];
            cout << a[i][j] << ' ';
        }
        cout << endl;  
    }
  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值