基础算法前缀和与差分

前言

本次博客会介绍一维和二维的前缀和,以及一维二维差分的基本使用,尽量画图,多使用配合文字

使大家理解,希望有所帮助吧

一维前缀和

问题描述

这里有一个长度为n的数组,我们要算出【2,5】区间的元素和

暴力思路

要计算一个数组区间的和可以直接把它遍历一遍,其实相信大家肯定可以敲出这个简单的代码

我们这里简单的敲一敲

复制代码
//这里可以改变数组的大小
#define N 10
int main()
{
	int arr[N] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("请输入两个数表示区间");
	//表示两个区间
	int left;
	int right;
	long long sum = 0;
	scanf("%d %d",&left,&right);
	for (int i = left; i <= right; i++)
		sum+=arr[i];
	printf("%lld",sum);
	return 0;
}

这里的时间复杂就是0(n)

如果我们要计算m次区间和的话时间复杂度为o(n*m)

前缀和思路

我们可以直接用一个sum数组分别去记录它的前n项和

数组的下边代表项数

举个例子

有一个数组 1 2 3 4 5 6 7 8 9 10

那么它的sum数组为 1 3 6 10 15 21 28 36 45 55

每一个元素都是前n项和 数组的下标+1代表几个元素的和

公式 sumi=sumi-1+arri;

这里是递推式,后一项由前一项得到,算了怕大家不懂

sum0=arr0

sum1=sum0+arr1

sum2=sum1+arr2

```````````

这下该懂了吧,我们可以通过sum数组来求区间和

看图

大家看到了,我们只要sumright-sumleft-1就可以解决问题 o(1)

区间分析

大家看 如果是0,5区间那么他就有可能会出现越界的情况呀

毕竟是sum5-sum-1,那不就错了吗

所以我们的sum数组应该从1开始的我们默认让sum0=0

这样就不会出现区间问题,而此时区间代表的就不是数组下标而是第几个数到第几个数

ok

看代码吧

复制代码
int sum[11] = {0};
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int l, r;
	printf("请输入两个数,表示左右区间");
	scanf("%d %d", &l, &r);
	int size = sizeof(arr) / sizeof(arr[0]);
	//计算前缀和数组
	for (int i = 1; i <=size; i++)
	{
		sum[i] = sum[i - 1] + arr[i-1];
	}
	int result = sum[r] - sum[l - 1];
	printf("%d",result);
	return 0;
}

这样就可以降低时间复杂度了

一维差分

问题描述

有一个 数组,我们要对 left,right 区间的元素进行加减操作 操作m次

暴力思路

还是这样,我们还是遍历一遍区间,然后进行操作

其实暴力代码还是一样的,这里还是别懒了,再给大家操作一遍

复制代码
//这里可以改变数组的大小
#define N 10
int main()
{
	int arr[N] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("请输入两个数表示区间");
	//表示两个区间
	int left;
	int right;
	scanf("%d %d",&left,&right);
    printf("请输入操作数");
    int a;
    scanf("%d",&a);
	for (int i = left; i <= right; i++)
		arr[i]+=a;
	for(int i=0;i<N;i++)
        printf("%d",arr[i]);
	return 0;
}

差分思路

我们先算一遍差分数组

比如 有一个数组arr10={1,2,3,4,5,6,7,8,9,10};

我们先算一个d10数组

d0=arr0 d1=arr1-arr0 d2=arr2-arr1 d3=arr3-arr2

······d9=arr9-arr8

那么d10={1,1,1,1,1,1,1,1,1,1};

差分数组的性质

1 大家发现没,差分和前缀和是逆运算,也就是我们可以通过前缀和的公式计算差分数组得到原数组

2 差分数组的前面元素加上或减去一个数,在进行前缀和后会把所加的数的影响给到后面的元素

可以举例

比如一个差分数组

0 0 0 0 0 0 0 0 0 0

我们让第一个数加上一个1 变成

1 0 0 0 0 0 0 0 0 0

通过前缀和,所求的原数组为

1 1 1 1 1 1 1 1 1 1

这种影响会从前到后影响

对吧,那么如何解决问题呢,只要控制影响,利用差分数组的逆过来求前缀和数组

最后把结果加入到所求的数组中完成任务

那我们还是画个图,来理解

接下来看代码

复制代码
//差分
//差分可以让某个区间全体加上或减去一个数
//除去差分数组可达到o(1)的时间复杂
int sub[20] = {0};
void fun(int left, int right, int num)
{
	sub[left] += num;
	sub[right+1]-=num;//只要数组的大小大于计算数组就不用担心越界问题
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int size = sizeof(arr) / sizeof(arr[0]);
	//差分其实是前缀的逆运算
	//也就是可以说差分后再前缀可以得到原来的数组
	//所以完全可以不用去算差分数组而是创建一个数组把它当成
	//差分数组,再求前缀和,把它与原来的数组相加可以得到结果
	fun(1, 2, 5);
	for (int i = 1; i < size; i++)
	{
		sub[i] += sub[i - 1];
	}
	for (int i = 0; i < size; i++)
		arr[i] += sub[i];
	for (int i = 0; i < size; i++)
		printf("%d ", arr[i]);
	return 0;
}

总结

这个逻辑实现确实比较的简单,但是仍然有很多的细节,尤其是边界问题,

这两种算法可以说非常常用,下次博客再写一写二维的前缀和差分吧

相关推荐
JieE2129 小时前
LeetCode 101. 对称二叉树|JS 递归 + 迭代双解法,彻底搞懂镜像判断
javascript·算法
JieE2121 天前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
Jack202 天前
HarmonyOS开发中错误处理策略:网络异常统一处理
算法
小小杨树2 天前
读懂色彩:拍照调色不再难
算法·计算机视觉·配色
JieE2122 天前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE2122 天前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
vivo互联网技术3 天前
CVPR 2026 | 全新强化学习框架 BeautyGRPO:重塑真实人像
算法·大模型·cvpr·影像
Darling噜啦啦3 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
用户497863050733 天前
(一)小红的数组操作
算法·编程语言