【基础算法练习】前缀和与差分模板

前缀和算法思想

用 O(N) 的复杂度构建前缀和数组,通过这种方式达成 O(1) 的时间来得到区间和,说是一种算法,其实可以说是一种常用的算法思想

差分算法思想

用 O(N) 的复杂度构建差分数组,通过这种方式达成 O(1) 的时间让一个区域内的值同时 + C

C++ 版本的前缀和模板

一维前缀和

vector<int> v(N), arr(N); // v 是原数组, arr 是前缀数组

for (int i = 1; i <= n; i++) arr[i] = arr[i - 1] + v[i];

cout << arr[r] - arr[l - 1] << endl;

v 就是题目给出的数组,arr 就是我们构建的前缀和数组,求一维前缀和的公式就是:arr[i] = arr[i - 1] + v[i]

如果我们要求区间 [ l,r ],只需要:arr[r] - arr[l - 1]

二维前缀和

vector<vector<int>> vv(N, vector<int>(N)), arr(N, vector<int>(N));

for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++)
        arr[i][j] = vv[i][j] + arr[i - 1][j] + arr[i][j - 1] - arr[i - 1][j - 1];

cout << arr[x2][y2] - arr[x1 - 1][y2] - arr[x2][y1 - 1] + arr[x1 - 1][y1 - 1] << endl;

二维前缀和的公式是:arr[i][j] = vv[i][j] + arr[i - 1][j] + arr[i][j - 1] - arr[i - 1][j - 1]

记忆方法: 把 i,j 位置本身(vv[i][j]),以及上面的前缀和,左边的前缀和加在一起,再减去他们共同的部分(加过两次的部分)

如果要求 (x1,y1) 到 (x2,y2) 这个区间内的值,用这个公式:arr[x2][y2] - arr[x1 - 1][y2] - arr[x2][y1 - 1] + arr[x1 - 1][y1 - 1]

记忆方法: 当前区域的前缀和,减去一个 x1-1 和一个 y1-1,分别配上 y2 和 x2,最后加上他们多减去的位置:arr[x1-1][y1-1]

(PS:这次没有 Golang 版本的代码,但其实都是一样的,开数组然后构建前缀和,不同语言没有任何差别,这里就摸鱼了)

C++ 版本的差分模板

一维差分

vector<int> v(N), arr(N);

void insert(int l, int r, int c) {
   
    arr[l] += c;
    arr[r + 1] -= c;
}

for (int i = 1; i <= n; i++) insert(i, i, v[i]);

insert(l, r, c);

for (int i = 1; i <= n; i++) arr[i] += arr[i - 1];

insert 函数的操作是让 [l,r] 的区间 + C

差分数组的性质就是,在 l 位置 + C,原数组 l 及之后的的区间值会全部 + C,让 r + 1 位置 - C,就能做到 O(1) 的时间复杂度,让原数组的 [l,r] 区间全部完成 + C 的操作

假设我们对差分数组 [l,l] 位置 + C,那其实就是让原数组的 l 位置 + C,我们就可以利用这个性质,通过 insert 操作通过原数组的值构建差分数组,之后还能复用 insert 方法完成区间值的修改

差分数组可以通过求自身的前缀和数组的形式,将差分数组转换成原数组,也就是:arr[i] += arr[i - 1]

二维差分

vector<vector<int>> vv(N, vector<int>(N)), arr(N, vector<int>(N));

void insert(int x1, int y1, int x2, int y2, int c) {
   
    arr[x1][y1] += c;
    arr[x2 + 1][y1] -= c;
    arr[x1][y2 + 1] -= c;
    arr[x2 + 1][y2 + 1] += c;
} 
                
for (int i = 1; i <= n; i++) 
    for (int j = 1; j <= m; j++)
        insert(i, j, i, j, vv[i][j]);
        
insert(x1, y1, x2, y2, c);

for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++)
        arr[i][j] += arr[i - 1][j] + arr[i][j - 1] - arr[i - 1][j - 1];

二维差分跟一维也是同理,而且他的 insert 计算和前缀和刚好相反,比较好记忆,二维前缀是分别减去 x1-1,y1-1,加上 x1y1 都 -1,而二维差分是分别减去 x2+1,y2+1,然后加上 x2y2 都 +1

相关推荐

  1. 基础算法练习前缀模板

    2024-01-30 01:38:02       35 阅读
  2. 算法前缀

    2024-01-30 01:38:02       12 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-30 01:38:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-30 01:38:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-30 01:38:02       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-30 01:38:02       20 阅读

热门阅读

  1. 算法每日一题: 最大合金数 | 二分

    2024-01-30 01:38:02       26 阅读
  2. Python入门指北七

    2024-01-30 01:38:02       31 阅读
  3. HTML — 区块元素

    2024-01-30 01:38:02       33 阅读
  4. ambari hdp 企业级安装实战

    2024-01-30 01:38:02       28 阅读
  5. 多端ftp上传下载导致程序crash问题排查

    2024-01-30 01:38:02       37 阅读
  6. Next.js 学习笔记(七)——样式

    2024-01-30 01:38:02       40 阅读
  7. Python入门学习指北

    2024-01-30 01:38:02       36 阅读
  8. 数据库SQL查询相关练习

    2024-01-30 01:38:02       30 阅读
  9. 域名被劫持了该怎么办

    2024-01-30 01:38:02       41 阅读