【入门级-算法-4、算法策略:差分】

一、概念

差分是一种处理区间修改和单点查询的高效技巧。它通过构建一个辅助数组(差分数组),将原数组的区间操作转化为对差分数组的单点操作,从而将时间复杂度从 O (n) 降至 O (1)。

二、差分的核心原理

差分通过构建一个辅助数组(差分数组)来简化原数组的区间更新。

首先进行差分数组的定义

给定原数组 a1...n,其差分数组 d1...n 定义为:

d1 = a1

d2 = a2 - a1

...

di = ai - ai-1(其中 i > 1)

原数组与差分数组的关系:差分数组的前缀和等于原数组。

d1 = a1

d2 = a2 - a1

d3 = a3 - a2

d4 = a4 - a3

...

也就是说,对任意 i,ai = d1 + d2 + ... + di。

这是差分能够反向推导原数组的关键。

三、差分的核心应用:区间更新

差分的最大价值在于高效处理"对原数组某一区间 l, r 内所有元素加 / 减一个值 k" 的操作。

区间更新的转化规则无需遍历原数组的 l, r 区间,只需对差分数组 d 做两处单点修改:

dl = dl+ k:表示从 l 位置开始,原数组所有元素增加 k。

dr+1= ar+1- ar

由于此时ar已经增加了k,而 ar+1没有变化,因此新的dr+1减少了k

即新的dr+1=旧的dr+1- k(若 r+1 <= n):表示从 r+1 位置开始,抵消之前的增加操作,确保仅 l, r 区间受影响。

操作流程示例

假设原数组 a = 1, 2, 3, 4, 5,需对 2,4 区间各元素加 2:

初始差分数组 d = 1, 1, 1, 1, 1

执行更新:d2 += 2 → d2 = 3;d5 -= 2 → d5 = -1

更新后差分数组 d = 1, 3, 1, 1, -1

求前缀和得到新原数组:a = 1, 4, 5, 6, 5,符合预期。

四、差分的适用场景

差分并非万能,它仅适用于特定类型的问题,主要包括:

多组区间更新 + 一次最终查询:例如多次给不同区间加值,最后输出完整数组。

线性结构数据:仅适用于一维数组或可转化为一维数组的场景(如二维差分需特殊处理)。

五、代码实现

题目:给定数组 a,多次执行:对 l, r 内所有数 +val,最后输出整个数组。

c 复制代码
#include <stdio.h>
#define N 100

int main() {
    int a[N] = {0};  // 原数组
    int d[N] = {0};  // 差分数组
    int n, m;
    int i;

    // 1. 输入数组长度 n
    printf("请输入元素个数 n:");
    scanf("%d", &n);

    printf("请输入 %d 个整数:", n);
    for (i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }

    // 2. 初始化差分数组
    d[1] = a[1];
    for (i = 2; i <= n; i++) {
        d[i] = a[i] - a[i - 1];
    }

    // 3. 操作次数 m
    printf("请输入操作次数 m:");
    scanf("%d", &m);

    // 4. 执行 m 次区间加操作
    while (m--) {
        int l, r, val;
        printf("输入 l r val:");
        scanf("%d %d %d", &l, &r, &val);

        d[l] += val;
        if (r + 1 <= n)
            d[r + 1] -= val;
    }

    // 5. 求前缀和,还原数组
    a[1] = d[1];
    for (i = 2; i <= n; i++) {
        a[i] = a[i - 1] + d[i];
    }

    // 6. 输出结果
    printf("最终数组:");
    for (i = 1; i <= n; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");

    return 0;
}

运行程序

输入:

请输入元素个数 n:5

请输入 5 个整数:1 2 3 4 5

请输入操作次数 m:2

输入 l r val:2 4 10

输入 l r val:1 3 5

过程:

原数组:1 2 3 4 5

操作 1:2,4 +10 → 1 12 13 14 5

操作 2:1,3 +5 → 6 17 18 14 5

输出结果:

最终数组:6 17 18 14 5

相关推荐
nhdh2 小时前
B+树揭秘:MySQL索引核心原理全解析
数据结构·b树·mysql
海上小飞龙2 小时前
【KMP算法-下篇】同一道题:Java 库函数 2600 微秒,手写 KMP 16 微秒
java·开发语言·算法
青少儿编程课堂3 小时前
后缀自动机解析:本质不同子串与最长重复片段统计
c++·python·算法·bfs·信息学竞赛
朝朝辞暮i3 小时前
C++ 第 12 课:局部变量、作用域、变量生命周期
开发语言·c++·算法
乐迪信息4 小时前
港口船舶逆行怎么管?AI防爆摄像机搭载智能检测算法
大数据·人工智能·深度学习·算法·计算机视觉
Sirens.5 小时前
Java并发锁详解:六类锁策略与 synchronized 底层原理
java·前端·算法
和裕5 小时前
全纸结构重型纸箱能否满足 1 吨以上设备出口熏蒸豁免要求?通关合规性全解析
大数据·运维·网络·人工智能·算法
tangguofeng6 小时前
不带头结点的链队操作集(不含InitFlag)(C语言版)
算法
苏打豆7 小时前
CRISP源码阅读——基于ROS2力矩反馈控制器与速度加速度零空间
c++·线性代数·算法·矩阵·机器人
蛋蛋的就会顺顺的7 小时前
hot100——矩阵
java·数据结构·算法·leetcode·力扣