leetcode练习笔记2022年9月

C语言常用函数库:

快速排序

<stdlib>: qsort

补充使用简介:
https://blog.csdn.net/ZDDWLIG/article/details/120209948

具体如下

  • 普通数组
  • 二维数组
  • 二维指针数组
#include <stdio.h>
#include <stdlib.h>


int cmp1(const void*a, const void*b)
{
	return (*((int*)a) - *((int*)b));
}

int cmp2(const void*a, const void*b)
{
	int *ax = (int*)a;
	int *bx = (int*)b;
	if(ax[0] != bx[0]) {
		return (ax[0] - bx[0]);
	}
	return (ax[1] - bx[1]);
}

int cmp3(const void*a, const void*b)
{
	int *ax = *(int**)a;
	int *bx = *(int**)b;
	if(ax[0] != bx[0]) {
		return (ax[0] - bx[0]);
	}
	return (ax[1] - bx[1]);
}

int main()
{
	printf("一维数组\n");

	int a[3] = { 3, 1 , 2};
    qsort(a, sizeof(a)/sizeof(int), sizeof(int), cmp1);
	for(int i = 0; i < 3; i++) {
        printf("%d\n", a[i]);
	}

    printf("二维数组\n");
	int b[3][2] = { {3, 1} , {2, 2}, {2, 1}};
    qsort(b, sizeof(b)/sizeof(b[0]), sizeof(b[0]), cmp2);
	for(int i = 0; i < 3; i++) {
        printf("%d %d\n", b[i][0], b[i][1]);
	}

	printf("二维数组指针\n");
	int c[3][2] = { {3, 1} , {2, 2}, {2, 1}};
	int *d[3] = { c[0], c[1], c[2]};

    qsort(d, sizeof(d)/sizeof(d[0]), sizeof(d[0]), cmp3);
	for(int i = 0; i < 3; i++) {
        printf("%d %d\n", d[i][0], d[i][1]);
	}

	return (0);
}

求最大最小值

<math.h>: fmax/fmin

需要重点学习的算法

周赛题目练习中遇到的经典算法记录:

参考:https://leetcode.cn/problems/divide-intervals-into-minimum-number-of-groups/solution/by-lfool-iri7/

「贪心 + 堆」「线段树」「差分数组」

差分数组:

参考博客《基础算法:差分讲解》

1.差分的基本概念:

如果有一数列 a[1],a[2],.…a[n]且令 b[i]=a[i]-a[i-1],b[1]=a[1]

那么就有

  • a[i]=b[1]+b[2]+.…+b[i] = a[1]+a[2]-a[1]+a[3]-a[2]+.…+a[i]-a[i-1]
    此时b数组称作a数组的差分数组

  • 换句话来说a数组就是b数组的前缀和数组 例:
    原始数组a:9 3 6 2 6 8
    差分数组b:9 -6 3 -4 4 2
    可以看到a数组是b的前缀和

  • 现在需求:将[l,r]区间中的数组元素a[i]均加上常数C,如果使用原始算法,则要扫描一下数组a,时间复杂度为O(n);如果使用差分算法则时间复杂度仅为O(1)。具体步骤如下:
    a.b[l] + C:当b[l] + C时,a[l]、a[l+1]、…、a[n]均会加C,原因是a[i] = b[1] + b[2] + … + b[i]
    b.b[r + 1] - C:由于需求是将数组a中[l,r]区间中的元素均加C,因此需要将b数组中a[r+1, n]区间中的元素都减去C。这样做才能够抵消b[l] + C步骤中将数组a中[r + 1, n]区间中的元素多加的C给抵消掉,实现真正将[l,r]区间中的数组元素a[i]均加上常数C. 引用

2. 差分数组应用练习题

例题1:有n个数,m个操作,每一次操作,将x~y区间的所有数增加z;
最后有q个询问,每一次询问求出x~y的区间和。

分析:首先我们得到一个原数组a,然后
设d[i]=a[i]-a[i-1] (1<i≤n,d[1]=a[1]);//差分数组
设f[i]=f[i-1]+d[i] (1<i≤n,f[1]=d[1]=a[1]);
设sum[i]=sum[i-1]+f[i] (1<i≤n,sum[1]=f[1]=d[1]=a[1])。//区间求和
在这里插入图片描述
例题2: 同样利用差分数组对某一区间的值进行修改,sum数组保存的就是前n项的和
只对区间两端的值进行修改,是因为每次的 f[i] 数组都包含着 f[i-1]+d[i],即如果在修改区间[left,right]内的话,从区间left开始以后的每一项都加上了修改值z,然后到最后一项right+1时就把z减掉
在这里插入图片描述
具体代码如下:

#include <stdio.h>
#include <stdlib.h>

#define N 10


int main()
{
	int a[N] = {1,2,3,4,5,6,7,8,9,0};
	int b[N] = {0};
	int f[N] = {0};
	int sum[N] = {0};
	int m = 3;
	int q = 2;
	b[0] = a[0];

    for (size_t i = 1; i < N; i++) {
		b[i] = a[i] - a[i-1];//差分数组
	}
	for(int i = 0, x, y, k; i < m; i++) {
        scanf("%d %d %d", &x, &y, &k);//区间x~y m个操作加k
		b[x] += k;
		b[y+1] -= k;
	}
    for (size_t i = 1; i < N; i++) {
		f[i] = f[i-1] + b[i]; //相当于原始数组a
		sum[i] = sum[i-1] + f[i];//求a[i]的前缀和
	}

	for (int i = 0, x, y; i < q; i++) {
		scanf("%d %d", &x, &y);
		printf("询问:%d ~ %d 之间的和是 %d", x, y, sum[y] - sum[x-1]);
	}
	
	return (0);
}