【C语言练习题】

喝汽水
在这里插入图片描述

20元->20空瓶
20空瓶->送10瓶
10瓶->送5瓶
5瓶-> 送2瓶+1瓶(存在)
3瓶->送1瓶+1瓶(存在)
2瓶->1瓶
总共喝了20+19瓶
总共喝了的数量分为两部分

  1. 实实在在买的
  2. 用空瓶子换的
int main()
{
	int money;
	int total;
	int empty;
	scanf("%d", &money);
	//直接买的
	total = money;
	empty = total;
	//送的
	while (empty > 1)
	{
		total += empty / 2;
		empty = empty / 2 + empty % 2;
	}
	printf("%d\n", total);
	return 0;
}

调整奇数偶数顺序
在这里插入图片描述

奇数在数组中前半部分,偶数在数组中后半部分,可以通过双指针来解决
在这里插入图片描述
left指向首元素,right指向尾元素,当left指向的元素不是偶数,left向后挪动直到指向偶数,right指向的元素不是奇数,right向前挪动直到right指向奇数
交换left和right指向的元素,重复上述动作直到left>=right

void Move(int* arr, int sz)
{
	int left = 0;
	int right = sz - 1;
	while (left < right)
	{
		//让left指向偶数
		while (arr[left] % 2 == 1 && left < right) left++;//循环条件保证数组不会因为全是奇数而越界
		//让right指向奇数
		while (arr[right] % 2 == 0 && left < right) right--;//循环条件保证数组不会因为全是奇数而越界
		//交换
		int tmp = arr[left];
		arr[left] = arr[right];
		arr[right] = tmp;
	}
}
int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7 ,8 };
	int sz = sizeof arr / sizeof arr[0];
	Move(arr, sz);
	for (int i = 0; i < sz; i++)
		printf("%d ", arr[i]);
	return 0;
}

猜名次
在这里插入图片描述

每个人都可能有5种状态,第一、第二、第三、第四、第五
每位选手说对了一半可以用条件表达式x+y==1(x、y表示事件)来表示

int main()
{
	int a, b, c, d, e;
	for (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++)
					{
						//保证a五人排名不重复
						if (a * b * c * d * e == 120)
						{
							//5个人都说对一半
							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)
							{
								printf("a=%d,b=%d,c=%d,d=%d,e=%d\n", a, b, c, d, e);
								return 0;
							}
						}
					}
				}
			}
		}
	}
	return 0;
}

猜凶手
在这里插入图片描述

从凶手的状态考虑有4种,凶手是a,凶手是b,凶手是c,凶手是d,三个人说真话可以表示为p+q+x+y==3

int main()
{
	char killer;
	for (killer = 'a'; killer <= 'd'; killer++)
	{
		if ((killer != 'a') + (killer == 'c') + (killer == 'd') + (killer != 'd') == 3)
		{
			printf("%c\n", killer);
				break;
		}
	}
	return 0;
}

从4个人的状态考虑每个人都有是凶手和不是凶手两种状态,因此还可以这么写

int main()
{
	char a, b, c, d;
	for (a = 0; a <= 1; a++)
	{
		for (b = 0; b <= 1; b++)
		{
			for (c = 0; c <= 1; c++)
			{
				for (d = 0; d <= 1; d++)
				{
					if ((a != 1) + (c == 1) + (d == 1) + (d != 1) == 3)
					{
						printf("%d %d %d %d", a, b, c, d);//1为凶手
						goto lip;
					}
					
				}
			}
		}
	}
lip:;
}

字符串左旋
在这里插入图片描述

可以暴力遍历,循环k次,每次把最左边的字符移动到最右边,比较简单,这里不再赘述
想要左旋转字符串,可以通过以下三步完成

  1. 逆序前k个字符
  2. 逆序后len-k个字符
  3. 逆序整个字符串(不包括结束符)
#include <string.h>
void Reverse(char* start, char* end)
{
	int left = 0;
	int right = end - start;
	while (left < right)
	{
		char tmp = start[left];
		start[left] = start[right];
		start[right] = tmp;
		left++;
		right--;
	}
}
char* LeftMoveStr(char* str, int k)
{
	k %= strlen(str);
	Reverse(str, str + k - 1);
	Reverse(str + k, str + strlen(str) - 1);
	Reverse(str, str + strlen(str) - 1);
	return str;
}
int main()
{
	char str[] = "abcdefgh";
	int k;
	scanf("%d", &k);
	printf("%s\n", LeftMoveStr(str, k));
	return 0;
}

字符串旋转结果
在这里插入图片描述

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

int IsLeftRotate(char* str, char* find)
{
	strncat(str, str, strlen(str));//注意这里不要使用strcat拼接自己
	return strstr(str, find) == NULL ? 0 : 1;
}
int main()
{
	char str1[20] = "abcdef";
	char find[8] = "cdefab";
	if (IsLeftRotate(str1, find))
	{
		printf("Yes\n");
	}
	else printf("No\n");
	return 0;
}

杨氏矩阵
在这里插入图片描述

我们仔细分析,不难发现,对于杨氏矩阵老说,右上角和左下角的元素是有特点的。右上角的元素是一行中最大的,一列中最小的。左下角的元素是一行中最小的,是一列中最大的。所以我们可以从右上角或者左下角开始查找。比如:从右上角开始查找的时候,右上角的元素比我们要查找元素小,我们就可以去掉右上角元素所在的这一行;右上角的元素比我们要查找的元素大,我们就可以去掉右上角元素所在的这一列。然后依然找右上角的元素继续和要查找的元素与比较。这样每一次比较去掉一行或者去掉一列。这个查找效率是高于遍历数组元素的,所以时间复杂度是小于O(N),也满足题目要求。

int FindKeyFromArr(int arr[][3], int* row, int* col, int key)
{
	int x = 0;
	int y = *col - 1;
	//循环终止条件
	while (x <= row - 1 && y >= 0)
	{
		if (arr[x][y] < key) x++;
		else if (arr[x][y] > key) y--;
		else
		{
			//返回找到的坐标
			*row = x + 1;
			*col = y + 1;
			return 1;
		}

	}
	return 0;
}
int main()
{
	int arr[3][3] = { {1,2,3}, {4,5,6}, {7, 8, 9} };
	int key;
	int x = 3; int y = 3;
	scanf("%d", &key);
	int ret = FindKeyFromArr(arr, &x, &y, key);
	if (1 == ret)
	{
		printf("找到啦!下标为(%d,%d)\n", x, y);
	}
	else printf("没找到!\n");

	return 0;
}

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值