c语言经典习题五

本文介绍了多个编程相关的挑战,包括易错的选择题,如字符串截断和大端存储的问题,以及逻辑推理题目,如猜名次问题和猜凶手游戏。此外,文章还详细讨论了杨辉三角的生成算法,并提供了不同的实现方式。同时,探讨了字符串左旋的不同方法,包括移动字符、三次逆序和拼接法。这些题目和解决方案展示了编程中的逻辑思维和问题解决技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言


一、易错选择题

1.字符串截断问题

在这里插入图片描述在这里插入图片描述
答案选c

方一:

a: 00000000 00000000 00000000 11001000
b: 00000000 00000000 00000000 01100100
由于转为char截断后
a:11001000
b: 01100100
由于打印为整数,进行整型提升:
a: 00000000 00000000 00000000 11001000
b: 00000000 00000000 00000000 01100100
a+b:00000000 00000000 00000001 00101100

由于c为char型,再次截断:
00101100
然后再整型提升:00000000000000000000000000101100

由此可得:a+b=300;c=44

方二:
由于unsigned char类型的取值范围只能是0~255。所以300超过了255。
直接计算超出多少,即求出c的值。300-255=45 ,由于是从0开始,因此还减1:45-1=44
在这里插入图片描述

2.大端问题

在这里插入图片描述
选a

a的地址为:0x00 00 12 34
a在内存中大端存储为:低 00 00 12 34 高
由于char类型,取一字节,为00。

二、

1.猜名次问题

在这里插入图片描述
思路:1.考虑到一共五个人,直接模拟推理有些太难,计算机最擅长的遍历此时就会派上用场,将每个人从第1到第5来一遍,则一共会产生5^5种可能性,这个只需要一个5层循环即可搞定。
2.但是这样会导致一些不期望出现的结果出现,因为没有查重,所以会出现两个人抢名次的情况,也就是两个人或者更多的人名次相同的情况,例如两个第二,三个第三这样的,所以即使满足了条件,也要查看一下五个人的名次是否重复。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	//a:(b==2)+(a==3)=1
	//b:(b==2)+(e==4)=1
	//c:(c==1)+(d==2)=1
	//d:(c==5)+(d==3)=1
	//e:(e==4)+(a==1)=1
	int a, b, c, d, e;
	for (int a = 1; a <= 5; a++)
	{
		for ( b = 1; b <= 5; b++)
		{
			for ( c = 1; c <= 5; c++)
			{
				for ( d = 1; d <= 5; d++)
				{
					for ( e = 1; e <= 5; e++)
					{
						if (
							((b == 2) + (a == 3) == 1)
							&& ((b == 2) + (e == 4) == 1)
							&& ((c == 1) + (d == 2) == 1)
							&& ((c == 5) + (d == 3) == 1)
							&& ((e == 4) + (a == 1) == 1)
							)
						{
							if (a * b * c * d * e == 120)
							{
								printf("a=%d b=%d c=%d d=%d e=%d", a, b, c, d, e);
							}
						}
					}
				}
			}
		}
	}
}

2.猜凶手

#include<stdio.h>
int main()
{
   int killer = 0;
   //分别假设凶手是a,b,c,d,看谁是凶手时满足3个人说了真话,一个人说了假话
   for (killer = 'a'; killer <= 'd'; killer++)
   {
    if ((killer != 'a') + (killer == 'c') + (killer == 'd') + (killer != 'd') == 3)
     printf("凶手是:%c", killer);
   }
   return 0;
}

3.杨辉三角

在这里插入图片描述
由于此题要打印整个杨辉三角的数据而非取出某一项,所以不可避免的一定是要填出每一项,没有偷懒的余地,那就老老实实的根据规律填空即可。按照题设的场景,能发现数字规律为:d[i][j] = d[i - 1][j] + d[i - 1][j - 1]。所以我们只要按照这个方法填表即可。

方一:
#include<stdio.h>
//1
//1 1
//1 2 1  a[2][1]=a[1][0]+a[1][1]
//1 3 3 1
//1 4 6 4 1
int main()
{
	int arr[10][10] = {0};//初始化非常重要
	int i;
	for ( i = 0; i < 10; i++)
	{
		int j = 0;
		for (j = 0; j <=i; j++)
		{
			
			if (j == 0||(i == j))
			{
				arr[i][j] = 1;
				
			}
			

			if (i >= 2)
			{
				arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
				
			}
			
		}
		
	}
	for (i = 0; i < 10; i++)
	{
		int j = 0;
		{
			for (j = 0; j <= i; j++)
			{
				printf("%d ", arr[i][j]);
			}
			printf("\n");
		}
	}
}
方二:
void yangHuiTriangle(int n)
{
	int data[30][30] = { 1 }; //第一行直接填好,播下种子
 
	int i, j;
 
	for (i = 1; i < n; i++) //从第二行开始填
	{
		data[i][0] = 1; //每行的第一列都没有区别,直接给1,保证不会越界。
		for (j = 1; j <= i; j++) //从第二列开始填
		{
			data[i][j] = data[i - 1][j] + data[i - 1][j - 1]; //递推方程
		}
	}
 
	for (i = 0; i < n; i++) //填完打印
	{
		for (j = 0; j <= i; j++)
		{
			printf("%d ", data[i][j]);
		}
		putchar('\n');
	}
}

改进:
由于在填第n行的杨辉三角时,只跟第n-1行的杨辉三角产生联系,不会跟之前的有联系,所以没必要保存每一行的杨辉三角,填一行打一行就行了,这样能让空间复杂度从n^2降低到n。但是在填数据的时候不能对之前的数据覆盖,所以需要从后向前填。而填杨辉三角顺序对结果是没有影响的,所以可以实现。

void yangHuiTriangle(int n)
{
	int data[30] = { 1 };
 
	int i, j;
	printf("1\n"); //第一行就直接打印了
	for (i = 1; i < n; i++) //从第二行开始
	{
		for (j = i; j > 0; j--) //从后向前填,避免上一行的数据在使用前就被覆盖
		{
			data[j] += data[j - 1]; //公式同上,由于变成了一维,公式也变简单了。
		}
     
		for (j = 0; j <= i; j++) //这一行填完就直接打印了。
		{
			printf("%d ", data[j]);
		}
		putchar('\n');
	}
}

4.杨氏矩阵

在这里插入图片描述
例如:
1 2 3
4 5 6
7 8 9
在此中找7。可以先与每一行最右边的比较,如果比他小,就往那一行左边依次比较。比他大,那就到下一行的最右边比较。依次即可找到。arr[0][2];arr[1][2];arr[2][2];arr[2][1];arr[2][0].

#include <stdio.h>
 
int findnum(int a[][3], int x, int y, int f) //第一个参数的类型需要调整
{
	int i = 0, j = y - 1; //从右上角开始遍历
	while (j >= 0 && i < x)
	{
		if (a[i][j] < f) //比我大就向下
		{
			i++;
		}
		else if (a[i][j] > f) //比我小就向左
		{
			j--;
		}
		else
		{
			return 1;
		}
	}
	return 0;
}
 
int main()
{
	int a[][3] = { {1, 3, 5},
				  {3, 5, 7}, 
				  {5, 7, 9} }; //一个示例
 
	if (findnum(a, 3, 3, 2))
	{
		printf("It has been found!\n");
	}
	else
	{
		printf("It hasn't been found!\n");
	}
 
	return 0;
}

5.字符串左旋

在这里插入图片描述
方法一:
移动字符的方式实现

#include<stdio.h>
#include<string.h>
int main()
{
	char a[20] = "abcdef";
	int n=strlen(a);
	int k;
	scanf("%d", &k);
	int i = 0;
	int time = k % n;//长度为5的情况下,
					//旋转6、11、16...次相当于1次,
					//7、12、17...次相当于2次,以此类推。
	while (time)
	{
		char temp;
		temp = a[0];
		

		for (i = 0; i < n-1; i++) //单次平移,注意这里要长度-1,否则i+1要越界
		{
			a[i] = a[i + 1];
		}
		a[i] = temp;

		time--;
	}
	printf("%s", a);
}

方二:利用3次逆序来实现。
abcdef—>cdefab
整体逆序:fedc ba
前部分逆序:cdef ba a[0]–>a[n-k-1]
后部分逆序:cdef ab a[n-k]–>a[n-1]

void reverse_part(char *str, int start, int end) //将字符串从start到end这一段逆序
{
	int i, j;
	char tmp;
 
	for (i = start, j = end; i < j; i++, j--)
	{
		tmp = str[i];
		str[i] = str[j];
		str[j] = tmp;
	}
}
 
void leftRound(char * src, int time)
{
	int len = strlen(src);
	int pos = time % len;
	reverse_part(src, 0, pos - 1); //逆序前段
	reverse_part(src, pos, len - 1); //逆序后段
	reverse_part(src, 0, len - 1); //整体逆序
}

方法三:选择拼接法,一次到位
abcdef—》cdefab
1)ab cdefab cdef
其中转化后的是1)的字串。

void leftRound(char * src, int time)
{
	int len = strlen(src);
	int pos = time % len; //断开位置的下标
	char tmp[256] = { 0 }; //更准确的话可以选择malloc len + 1个字节的空间来做这个tmp
	
	strcpy(tmp, src + pos); //先将后面的全部拷过来
	strncat(tmp, src, pos); //然后将前面几个接上
	strcpy(src, tmp); //最后拷回去
}

6.字符串旋转结果

在这里插入图片描述
本题当然可以将所有旋转后的结果放到一个数组里,然后进行查找,但是这种做法既不好操作,也太费事,但是这题有一个很简单的做法:
其实ABCDE无论怎么旋,旋转后的所有结果,都包含在了ABCDEABCD这个字符串里了。
所以做法很简单,只需要将原字符串再来一遍接在后面,然后找一找待查找的字符串是不是两倍原字符串的子集即可。

int findRound(const char * src, char * find)
{
	char tmp[256] = { 0 }; //用一个辅助空间将原字符串做成两倍原字符串
	strcpy(tmp, src); //先拷贝一遍
	strcat(tmp, src); //再连接一遍
	return strstr(tmp, find) != NULL; //看看找不找得到
}

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值