C语言:刷题总结(3)

C语言的学习告一段落,本文是对近期学习C语言的刷题总结,题目大部分来自牛客网&力扣。

本篇文章是C语言本阶段的最后一篇文章,结束了几个月的学习,接下来会写一些关于Java的博客,后面有机会的话还会再继续来完善C语言内容。

题目十五:数对

题目描述:一个正整数数对(x,y),x和y的值均不大于n,并且x%y的值大于等于k。

输入描述:输入包括两个正整数n, k(1 <= n <= 10 ^ 5, 0 <= k <= n - 1)。
输出描述:对于每个测试用例, 输出一个正整数表示可能的数对数量。

思路:一开始的想法是直接用两个循环暴力求解出符合的数对个数,但是时间复杂度过大,所以编译不通过。这里通过一个例子来引出另一种思路: 假设输入 n=10 , k=3 ;
当 y <= k 时,意味着任何数字取模y的结果都在 [0, k-1]之间,都是不符合条件的。
当 y = k+1=4 时,x符合条件的数字有 3,7
当 y = k+2=5 时,x符合条件的数字有 3,4,8,9
当 y = k+3=6 时,x符合条件的数字有 3,4,5,9,10
当 y = k+n时,
x小于y当前值,且符合条件的数字数量是:y-k个,
x大于y当前值,小于2*y的数据中,且符合条件的数字数量是:y-k个
从上一步能看出来,在y的整数倍区间内,x符合条件的数量就是 (n / y) * (y - k)个
n / y 表示有多少个完整的 0 ~ y区间, y - k 表示有每个区间内有多少个符合条件的数字
最后还要考虑的是6...往后这种超出倍数区间超过n的部分的统计
n % y 就是多出完整区间部分的数字个数,其中k以下的不用考虑,则符合条件的是 n % y - (k-1) 个
这里需要注意的是类似于9这种超出完整区间的数字个数 本就小于k的情况,则为0
得出最终公式:(n / y) * (y - k) + ((n % y < k) ? 0, (n % y - k + 1));

实现代码:

#include <stdio.h>
int main()
{
	long n = 0;
	long k = 0;
	scanf("%ld %ld", &n, &k);
	if (k == 0)
	{
		printf("%ld\n", n * n);
	}
	else
	{
		long count = 0;
		for (long y = k + 1; y <= n; y++)
		{
			count += ((n / y) * (y - k)) + ((n % y < k) ? 0: (n % y - k + 1));
		}
		printf("%ld\n", count);
	}
	return 0;
}

题目十六:旋转字符串问题——左旋转字符串

题目描述:输入k,输出左旋转k个字符后的字符串

思路一:常规方法,将第一个字符存起来,其他字符都向前移动一位,最后将存起来的那个字符复制到最后,依次循环k次,就可以得出结果

实现代码:

#include <stdio.h>
#include <string.h>

void left_move(char* arr, int k)
{
	int len = strlen(arr);
	while (k--)
	{
		char ret = *arr;
		int i = 0;
		for (i = 0; i < len - 1; i++)
		{
			*(arr + i) = *(arr + i + 1);
		}
		*(arr + len - 1) = ret;
	}
}

int main()
{
	char arr[] = "abcdef";
	int k = 0;
	scanf("%d", &k);
	left_move(arr, k);
	printf("%s\n", arr);
	return 0;
}

思路二:三逆序实现旋转,假如是旋转k位,则在第k位的位置将这个字符串分隔为两个字符串,然后将这两个字符串分别逆序,最后再将整个字符串逆序一遍,也可以得出结果

实现代码:

void reverse(char* left, char* right)
{
	while (left < right)
	{
		char ret = *left;
		*left = *right;
		*right = ret;
		left++;
		right--;
	}
}

void left_move(char* arr, int k)
{
	int len = strlen(arr);
	k %= len;
	reverse(arr, arr + k - 1);
	reverse(arr + k, arr + len - 1);
	reverse(arr, arr + len - 1);
}

int main()
{
	char arr[] = "abcdef";
	int k = 0;
	scanf("%d", &k);
	left_move(arr, k);
	printf("%s\n", arr);
	return 0;
}

题目十七:杨氏矩阵

题目描述:有一个三维数组,数组的每行从左到右是递增的,每列从上到下是递增的.。在这个的数组中查找一个数字是否存在。

思路:本题最简单、最暴力的思路就是直接把整个三维数组遍历一遍,但是有时候是不能够通过测试用例的,这里介绍一种时间复杂度较低的且比较常规的思路——三维杨氏矩阵九个元素中只有两个元素是符合的(斜对角线顶点的两个元素,也就是第一行第三列和第三行第一列的两个元素),选其中的任意一个都可以,这里我用第一行第三列的元素(暂且称之为k)来实现,如果查找的数小于k的值,那么就来k前面的两个元素查找即可,如果是大于k的值,那么则找本列下一行的元素,再重复上面的比较,直到找到所要查找的元素,返回该元素坐标,如果查找是超出三维数组的界限,那么则可以判断该数组中并无这个数。

实现代码:

#include <stdio.h>

void find_int_arr(int arr[3][3], int* px, int* py, int k)
{
	int x = 0;
	int y = *py - 1;
	while (x <= *px - 1 || y >= 0)
	{
		if (arr[x][y] > k)
		{
			y--;
		}
		else if (arr[x][y] < k)
		{
			x++;
		}
		else
		{
			*px = x;
			*py = y;
			return;
		}
	}
	*px = -1;
	*py = -1;
	return;
}

int main()
{
	int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
	int k = 0;
	int x = 3;
	int y = 3;
	scanf("%d", &k);
	find_int_arr(arr, &x, &y, k);
	if (x == -1 && y == -1)
	{
		printf("找不到\n");
	}
	else
	{
		printf("找到了,下标是:(%d,%d)", x, y);
	}
	return 0;
}

题目十八:找单身狗

题目描述:一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。编写一个函数找出这两个只出现一次的数字。

思路:我们在前面的题目中就已经知道:只需要把数组中的所有数都异或在一起,就可以找出数组中只出现一次的数字。但是这道题相对于之前的那道题,还是有不同之处的,总体来说也会增加一个难度,因为该题是要找出数组中两个只出现一次的数字,乍一看,感觉还是挺类似的,但是仔细想想,如果像之前那样全部异或起来的话,只能够得出一个错误的值,所以这里就想到一个思路——就是将这个数组分为两部分,把两个只出现一次的数字分别分到两个组里面去,然后分别异或找出来即可。那么该如何识别出并将两个数分到两个组里面去呢?第一步,将数组中全部数字都异或起来;第二步,寻找异或之后的二进制有那个位按位与1之后值是1,是1则可以说明这两个只出现一次的数字在二进制中这一位是不相同的,相异或之后才会是1;第三步,将二进制中以刚才得出的不同位为准,就可以将这些数字分为两组,这两个只出现一次的数字分在不同组中了。这样就可以得出最后的结果。

实现代码: 

#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,1,2,3,4,6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//1.先将全部数异或在一起
	int ret = 0;
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		ret ^= arr[i];
	}
	//2.计算ret的二进制第几位是1
	int pos = 0;
	for (i = 0; i < 32; i++)
	{
		if (((ret >> i) & 1) == 1)
		{
			pos = i;
			break;
		}
	}
	//3.按pos位是0或1来对数组进行分组
	int n = 0;
	int m = 0;
	for (i = 0; i < sz; i++)
	{
		if (((arr[i] >> pos) & 1) == 1)
		{
			n ^= arr[i];
		}
	}
	m = ret ^ n;
	printf("%d %d\n", n, m);
	return 0;
}

题目十九:判断字符串是否是另一字符串旋转得来的

题目描述:判断字符串是否是另一字符串旋转得来的

思路:大多数人受之前旋转字符串代码的影响,对这道题的第一想法应该都是先旋转字符串再来进行判断是否相等,如此循环。但是对于这道题还有一种更加简便的方法——拷贝自身字符串并添加到后面的位置,再通过字符串查找,来判定是否存在,进而解决这道题。

实现代码:

#include <stdio.h>
#include <string.h>
int main()
{
	char str[20] = "abcde";
	char* sub = "cdeab";
	char* tmp = strncat(str, str, 5);
	char* ret = strstr(tmp, sub);
	if (ret == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		printf("%s\n", ret);
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蔡欣致

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值