《算法竞赛入门经典(第二版)》第三章 数组和字符串

数组

知识点

头文件<string.h>

1.memcpy
规定有a,b两个整型数组,如果要从数组a复制k个元素到b数组当中,就可以使用memcpy,写成 (b, a, sizeof(int)*k)。如果需要把a数组全部复制到b数组上,则写成 memcpy(b, a, sizeof(a))

2.memset
是用来设置内存的,将内存中的值以字节为单位设置成想要的内容。
例如memset(a,0,sizeof(a))就是将a数组的所有元素设置成0。这种方法相较于用for初始值方便了许多。

蛇形填数

在这里插入图片描述
代码实现:

#include<stdio.h>
#include<string.h>
int b[10000][1000];
int main()
{
	int n, x, y, tot = 0;
	scanf("%d", &n);
	memset(b,0,sizeof(b));
	tot = b[x = 0][y = n - 1] = 1;
	while (tot < n * n)
	{
		while (x + 1 < n && !b[x + 1][y]) b[++x][y] = ++tot;
		while (y - 1 >=0 && !b[x][y - 1]) b[x][--y] = ++tot;
		while (x - 1 >=0 && !b[x - 1][y]) b[--x][y] = ++tot;
		while (y + 1 < n && !b[x][y + 1]) b[x][++y] = ++tot;
	}

	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			printf("%3d", b[i][j]);
		}
		printf("\n");
	}
	
	return 0;
}

题目解析:
对于这种类型的题目,我认为最重要的事情就是分析题目,找出其中的规律,其实不难发现,它是按照类似螺旋的方式进行数据递增的,如下图展示
在这里插入图片描述
很容易发现从1-16每一步走的方向是:下下下 左左左 上上上 右右 下下 左 上。简而言之,它总是按照下左上右的顺序进行移动,那么现在有一个新的问题:它改变移动方向的依据是什么呢?首先,我们规定的矩形的大小,如果一旦超出矩形的边界,它的方向肯定会改变(例如:4->5);其次,在移动的过程中,我们可能会碰到我们之前已经到过的地方,这个时候也是需要改变方向的(12->13)。

代码解析:
1.我们使用了二维数组,因为我们的图形类似于一个矩阵,确定一个数据的具体位置需要竖向和横向的位置。
2.我们输入了n来表示矩形的大小,总大小即为n*n。
3.初始化棋盘为0,便于后续判断需要改变方向的重要依据
4.接着,我们需要从1开始依次填入。我们设置输入数据的坐标为(x,y),则一开始的坐标为x=0,y=n-1,即第0列,第n-1行(行列的范围均为0~n-1),然后根据刚刚分析出来的顺序,先向下,直到不能填,再左,再上,再右。

注意事项:
1.有人可能会发现x+1可能会等于n,这样访问二位数组就会越界,进行非法访问。但是“&&”是短路运算法,如果前者已经为假了,则不会计算后面的内容了(这和我们创立链表有类似的地方)

小提示

在算法竞赛中,常常难以精确计算出需要的数组大小,数组一般会声明得稍大一些。
在空间充足的情况下,浪费一点不会有太大影响

比较大的数组应该声明在函数外,否则程序可能无法执行

在输出数据的时候,为了避免出现多余的空格,常常会设置一个标志变量first,来表示当前要输出的元素是否为第一个。
int first=1; if(first) first=0;else printf(" ");

在很多情况下,最好是在做一件事之前检查是不是可以做,而不要做完后后悔。因为“悔棋”往往比较麻烦

字符数值

知识点

三种输出函数

1.printf: 输出的结果在屏幕上(控制台);
2.fprintf: 输出到文件中;
3.sprintf 输出到字符串当中。
使用前两种一般不需要考虑空间大小,但是输出到的字符串必须保证有足够大的空间。一般是字符个数+1(‘\0’)。

小提示

c语言中的字符型由char来表示,它实际储存的是字符的ASCⅡ码。字符常量可以用单引号法表示。在语法上可以把字符当做int型来使用。

如果是一个字符串数组char a[n],可以用scanf(“%s”,s[i])来读取第i个字符串。
当scanf(“%s”,a)读取到空白字符会停下来。

由于字符串的本质是数组,所以它也不是“一等公民”,只能用strcpy(a,b),strcmp(a,b),strcat(a,b)来执行赋值,比较和连接操作,而不能用简单的“=”“==”等运算符。上述函数都在string.h头文件中。

少用“++”,“–”,“+=”等可以修改变量值的运算符,建议每条语句最多只使用一次这种运算符,并且所修改的变量在整条语句中只出现一次。滥用则可能带来许多隐蔽的问题。
比如下面这个代码执行的结果:
在这里插入图片描述

竞赛题目选讲

知识点

1.字典序:

小提示

fgetc(fin),读取一个打开的的文件fin,读取一个字符,然后返回一个int值。那么会有人问为什么不是char呢?因为如果文件结束,fget将返回一个特殊标记EOF,它并不是一个char。如果强制转换成char,将无法把特殊字符和普通字符区分开。
但是如果要标准输入读取一个字符,可以用getchar(),它等价于fgetc(stdin)。
并且在使用fgetc和getchar时,应该避免写出和操作系统相关的程序。

fgets(buf,maxn,fin)将读取完整的一行放在字符数组buf中。应当保证buf足够存放下文件的一行内容。除了在文件结束前没有遇到"\n"这种特殊情况外,buf总是以"\n"结尾。当一个字符都没有读到的时候,fgets返回NULL。

C语言并不禁止程序读写“非法内存”。所以gets(s)存在缓冲区溢出漏洞,不推荐使用。

对于一些竞赛题,善用敞亮数组往往能简化代码。
定义常量数组时不需要指明大小,编译器可以完成计算。

头文件ctype.h中定义的isalpha,isdigit,isprint等工具可以用来判断字符的属性,而toupper,tolower等工具可以用来转换大小写。
如果ch是大写字母,则ch-'A’就是它在字母表中的序号(A的序号为0,B的序号为1…)
如果ch是数字,则ch-'0’就是这个数字的数值本身。

  • 23
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值