算法第三章 数组和字符串

很久没有学习算法了,今天来看看数组吧。==
先复习一下C语言知识点:
1.scanf 和 gets :
都能接收字符串,假如char a[ 10 ],scanf("%s",&a);  gets(a);
区别就是scanf不能接收空格,Tab,回车,只会输出空格之前的字符。gets能全部接收并用\0代替\n,回车键不会留在输入缓冲区中。比如输入abc  fgh,用scanf只能输出abc ,用gets 输出的是abc  fgh 。
2.printf 和 puts:
都能输出字符串,但是puts()在输出字符串时会将’\0’自动转换成’\n’进行输出,就是输出完字符串后会自动换行。
3.getchar 和 putchar:
这两个函数是用来获取和显示字符的,每次只能处理一个字符。如果想通过这两个函数实现输入多个字符:比如以#作为结束。
char ch;
ch=getchar();
while(ch!='#')
{
       putchar(ch); 
       ch=getchar();
}
4. 比较大的数组应尽量声明在 main 函数外,否则程序可能无法运行。
5. 从数组 a 复制k 个元素到数组 b ,可以这样做: memcpy b, a,sizeof(int) * k );
   #include <string.h>   全复制过去:memcpy(b,a,sizeof(a));
6.关于字符数组后边来讲。
7.memcpy 和 strcpy:
strcpy一般用于字符串的复制,遇到\0结束(会拷贝结尾的\0),没有指定长度,容易溢出。memcpy对复制类型没有限制,可以指定复制长度,更安全。
8.函数strchr (s,c)查找字符串s中首次出现字符c的位置,返回首次出现c的位置的指针,如果s中不存在c则返回NULL。
9.for循环里如果只有一条语句,可以不加大括号,多条语句必须加。双重循环外边的for里只有一个内循环语句,也可以不加,但是内循环里有多条语句的话必须加大括号。if 括号里如果不加的话只执行一条,我习惯都加大括号,但是答案里基本不加,看不懂所以查了查。
10. sprintf 函数:把整数打印到字符串中。sprintf(s, "%d", 123); //产生"123"。经常用来用来将整型转化为字符串。

3.1开灯问题

开灯问题。有 n 盏灯,编号为 1 n 。第 1 个人把所有灯打开,第 2 个人按下所有编号为 2的倍数的开关(这些灯将被关掉),第3 个人按下所有编号为 3 的倍数的开关(其中关掉的灯将被打开,开着的灯将被关闭),依此类推。一共有k 个人,问最后有哪些灯开着?输入n k ,输出开着的灯的编号。 k n ≤1000
//0:灯打开
//1:灯关闭 
#include <stdio.h>
#include <malloc.h>
int main()
{
	int n,k,*list;//n盏灯 k个人 
	int i=0,j=0,t=0,m=0;  //循环变量 
	scanf("%d%d",&n,&k);
	list=(int*)malloc(sizeof(int)*n);
	for(i=0;i<n;i++)
	{
		list[i]=1;//默认灯的状态 
	}      
	for(j=1;j<=k;j++)//第几个人 
	{
		for(t=1;t<=n;t++)//灯的序号 
		{
			if(t%j==0)
			{
				list[t]=!list[t];//灯的状态取反 
			}
		}
	}
	for(m=1;m<=n;m++)
	{
		if(list[m]==0)
		{
			printf("%d ",m);
		}
	}
	return 0;
}

 注:!是逻辑取反,把非零变成0,0变成1。~是按位取反,把二进制中的0变成1,1变成0。

先保存一段代码:

#include <stdio.h>
#include <malloc.h>
int main()
{
    int  **p;  //定义二维指针。
    int  m,n; //行数和列数。
    int  i,j;
    scanf ("%d%d",&m,&n);  //输入行数和列数。
    p = (int **)malloc( sizeof(int*)*m); //申请一组一维指针空间。
    for(i=0;i<m;i++)
        p[i]=(int*)malloc(sizeof(int)*n); 
    for(i=0;i<m;i++)
        for (j=0;j<n;j++)
            scanf ("%d",&p[i][j]); //输入第i行第j列的数据。其中&p[i][j]也可以写作p[i]+j或者是 *(p+i) + j. 功能相同。
     
    printf ( "输入的数组为%d行%d列:\n" , m, n);
    for (i=0;i<m;i++)
    {
        for (j=0;j<n;j++) //这个循环可以输出一行元素。
            printf ("%d ", p[i][j]); //输出i行j列的元素。
        printf ( "\n" ); //每行输入结束加换行符。
    }
     
     //释放内存
    for (i=0;i<m;i++)
        free(p[i]);
    free (p);
     
    return  0;
}

3.2 蛇形填数

效果:

 移动轨迹:从第0行,第n-1列开始,下下下,左左左,上上上,右右,下下,左,上。

先给x赋值0,给y赋值为n-1,然后马上把它们作为数组a的下标,可以合并成一行代码。

然后tot和a[0][n-1]都要赋值1,也可以合并完成。简洁,并且没有牺牲程序的可读性。

a[x+1][y]==0  可以写成 !a[x+1][y]。

#include <stdio.h>
#include <string.h>
#define maxn 20
int a[maxn][maxn];
int main()
{
	int n,x,y,tot=0;
	scanf("%d",&n);//输入阶数n 
	memset(a,0,sizeof(a));
	tot=a[x=0][y=n-1]=1;
	while(tot<n*n)
	{
		while(x+1<n&&!a[x+1][y])  a[++x][y]=++tot;
		while(y-1>=0&&!a[x][y-1]) a[x][--y]=++tot;
		while(x-1>=0&&!a[x-1][y]) a[--x][y]=++tot;
		while(y+1<n&&!a[x][y+1])  a[x][++y]=++tot;
	}
	for(x=0;x<n;x++)
	{
		for(y=0;y<n;y++) 
		{
			printf("%3d",a[x][y]);
		}
		printf("\r\n");
	}
	return 0;
}

3.3 竖式问题

找出所有形如 abc*de (三位数乘以两位数)的算式,使得在完整的竖式中,所有数字都属于一个特定的数字集合。输入数字集合(相邻数字之间没有空格),输出所有竖式。每个竖式前应有编号,之后应有一个空行。最后输出解的总数。具体格式见样例输出(为了便于观察,竖式中的空格改用小数点显示,但所写程序中应该输出空格,而非小数点)。
这个题的意思是:输入几个数,然后输出效果是这样的:为什么输入2357?得保证竖式中所有出现的数都在这个2357里面才行。
#include <stdio.h>
#include <string.h>
int main()
{
	int abc,de,x,y,z,i,ok=1;
	int count=0;
	char s[20],buf[99];
	scanf("%s",s);
	for(abc=111;abc<1000;abc++)
	{
		for(de=11;de<100;de++)
		{
			x=abc*(de%10);//第一层 
			y=abc*(de/10);//第二层 
			z=abc*de;	  //第三层 
			sprintf(buf,"%d%d%d%d%d",abc,de,x,y,z);//把整型打印到字符数组里 
			ok=1;
			for(i=0;i<strlen(buf);i++)
		
				if(strchr(s,buf[i])==NULL)//在s中查找buf[i]不存在 
				{
					ok=0;
				}
				if(ok==1)//存在 输出 
				{
					printf("<%d>\n",++count);
					printf("%5d\nX%4d\n-----\n%5d\n%4d\n-----\n%5d\n\n", abc, de, x, y, z);
				}
		}		
	}
		printf("The number of solutions = %d\n", count);
		return 0;
}

附上strchr的用法:

 1.在这个题中,sprintf 输出到字符串(要保证字符串足够大),printf 输出到屏幕,fprintf 输出到文件(关于文件我记着前面的文章里提到过,但是没有学文件的操作);然后strchr函数是用来在一个字符串中查找单个字符的。

2.C语言中的字符串是以‘\0’结尾的,strlen(s)返回结束标记之前的字符个数,s[0]到s[strlen(s)-1]。

这个题我写的是这样的:

#include <stdio.h>
#include <string.h>
void main()
{
	int abc,de,i,count1=0,flag=1;//三位数*两位数 
	int c1,c2,c3;//第一层 第二层 第三层(结果) 
	char s[20],buf[113];
	scanf("%s",s);//输入数字集合 
	for(abc=111;abc<1000;abc++)
	{
		for(de=11;de<100;de++)
		{
			c1=abc*(de%10);
			c2=abc*(de/10);
			c3=abc*de;
			memcpy(&buf[0],s,20);
			memcpy(&buf[20],&abc,3);
			memcpy(&buf[23],&de,2);
			memcpy(&buf[25],&c1,4);
			memcpy(&buf[29],&c2,4);
			memcpy(&buf[33],&c3,5);
			flag=0;
			for(i=0;i<strlen(buf);i++)
			{
				if(strchr(s,buf[i])==NULL)
				{
					flag=1;	
				}
				if(flag==0)
				{
				printf("%5d\nX%4d\n-----\n%5d\n%4d\n-----\n%5d",abc,de,c1,c2,c3);
			 	}  
			}		
		}
	}
	
}

不对可能是memcpy复制过去的有空格所以就一直输出,个人感觉。。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值