C语言练习6
前言
"宝剑锋从磨砺出,梅花香自苦寒来。"人类的美好理想,都不可能唾手可得,都离不开筚路蓝缕、手胼足胝的艰苦奋斗。我们的国家,我们的民族,从积贫积弱一步一步走到今天的发展繁荣,靠的就是一代又一代人的顽强拼搏,靠的就是中华民族自强不息的奋斗精神。
编程题
一,输入一个字符串和一个整数 k ,截取字符串的前k个字符并输出
🌟输入描述:
1.输入待截取的字符串
2.输入一个正整数k,代表截取的长度
💫输出描述: 截取后的字符串
OJ链接【牛客网题号: HJ46 截取字符串】【难度:简单】示例:
输入:abABCcDEF 6
输出:abABCc
💡分析:
截取字符串前 n 个字符,只需要将数组 n 下标位置的数据替换为字符串结尾标志即可
c
🔑 代码实现
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
char str[1001] = { 0 };
while (scanf("%s", str) > 0)
{
int n = 0;
scanf("%d", &n);
str[n] = '\0';
printf("%s\n", str);
}
return 0;
}
💯运行结果:
二,1、牛牛以前在老师那里得到了一个正整数数对 (x, y) , 牛牛忘记他们具体是多少了。但是牛牛记得老师告诉过他: x和 y 均不大于 n , 并且 x 除以 y 的余数大于等于 k 。牛牛希望你能帮他计算一共有多少个可能的数对。
🌟输入描述::输入包括两个正整数 n,k(1 <= n <= 10^5, 0 <= k <= n - 1) 。
💫输出描述:对于每个测试用例, 输出一个正整数表示可能的数对数量。
OJ链接:【牛客网题号: WY49 数对】【难度:简单】
示例:
输入:5 2
输出:7
说明:满足条件的数对有(2,3),(2,4),(2,5),(3,4),(3,5),(4,5),(5,3)
💡分析:
1,暴力破解:将 x 和 y 分别遍历 [1, n] ,进行判断当 x % y > k 时统计计数 count++ 即可,但是这样的话当 n 的值非常大的时候循环次数将非常恐怖,需要循环 n^2 次。
>2,由题目要求我们可以很显然的到两个数学公式① 1≤x,y≤n ② k≤x%y
接下来我们分情况讨论:
当y<k时,任何一个x%y得到的结果都在[0,y-1]之间,显然y-1 < k 违背公式② k≤x%y,因此推导出y应当>k
那么当y>k时
这里我们讨论x在[y,2y-1]区间内,此时x%y等价于x-y,即y≤x≤2y-1,0≤x-y≤y-1
x%y或者说x-y得到的结果都在[0,y-1]之间,这个结果也就可以拆分成[0,k-1]与[k,y-1],显然此时有y-1 - k +1个x可以得到后者.如下图所示.也就是说有y-k个(x,y)使得x-y≥k
那么当x在[2y,3y-1]区间内呢?如果这个区间范围没超过n那么依旧有y-k个(x,y)使得x%y≥k,但是如果超过n了呢?那就需要看n具体在区间的哪个位置了.
那么对于任意一个y,我们有多少个长度为y的区间在范围n内?答案是(n / y)个,这样就有 (n / y)* (y - k) 个数对.对于最后一个区间,用 ((n % y < k) ? 0 : (n % y - k + 1))即可.
因此对于任意一个y,会有(n / y) * (y - k) + ((n % y < k) ? 0 : (n % y - k + 1));个x使得x%y≥k.
c
🔑 代码实现
1,
//运行超时
int main()
{
long n = 0;
long k = 0;
long x = 0;
long y = 0;
long count = 0;
scanf("%ld%ld", &n, &k);
for (x = 1; x <= n; x++)
{
for (y = 1; y <= n; y++)
{
if (x % y >= k)
count++;
}
}
printf("%ld\n", count);
return 0;
}
2,
#include <stdio.h>
int main()
{
long n, k;
while (~scanf("%ld %ld", &n, &k))
{
if (k == 0)
{
printf("%ld\n", n * n);//任意数对的取模结果都是大于等于0的
continue;
}
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;
}
💯运行结果:
3,给定一个长度为n的数组 nums ,请你找到峰值并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个所在位置即可。
1.峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于
2.假设 nums[-1] = nums[n] = 负无穷小
3.对于所有有效的 i 都有 nums[i] != nums[i + 1]
OJ链接【牛客网题号: NC107 寻找峰值】【难度:简单】
示例:
输入:[2,4,1,2,7,8,4]
返回值:1
说明:4和8都是峰值元素,返回4的索引1或者8的索引5都可以
输入:[5,3,4,2,6]
返回值:0
说明:-1作为下标或者n下标位置都表示负无穷小, 则0号下标5是峰值,或者4号下标6也是峰值
💡分析:
step1:边界情况处理,1个元素前后都是负无穷 以及 0号位置大于1号位置,-1位置负无穷的情况
step2:末尾位置数据大于上一个位置数据,而nums[numsLen]负无穷的情况
step3:除首位外中间元素用二分查找,中间元素大于右边元素说明峰值在左边包括当前位置,否则左边肯定有峰值
c
🔑 代码实现
//找峰值
int findPeakElement(int* num, int numslen)
{
// write code here
//边界情况处理,1个元素前后都是负无穷 以及 0号位置大于1号位置,-1位置负无穷的情况
if (numslen == 1)
return 0;
//末尾位置数据大于上一个位置数据,而nums[numsLen]负无穷的情况
if (num[numslen - 1] > num[numslen - 2])
return numslen - 1;
int left = 0;
int right = numslen - 1;
int mid = 0;
while (left < right)
{
mid = left + (right - left) / 2;
if (num[mid] > num[mid + 1])//中间比右边大,意味着左肯包包括当前位置定有个峰值
right = mid;
else//否则在右边肯定有个峰值
left = mid + 1;
}
return left;
}
4,现在有一个长度为 n 的正整数序列,其中只有一种数值出现了奇数次,其他数值均出现偶数次,请你找出那个出现奇数次的数值。
🌟输入描述:第一行:一个整数n,表示序列的长度。第二行:n个正整数ai,两个数中间以空格隔开。
输出描述:一个数,即在序列中唯一出现奇数次的数值。
OJ链接【牛客网题号: KS33 寻找奇数】【难度:简单】
示例:
输入:5
2 1 2 3 1
输出:3
💡分析:
异或:二进制比特位相同则0, 不同则1.
两个相同的数字异或得到的是0, 基于这个思路,这道题对数组中的所有数据进行逐一异或就可以解决得到奇数次的数字,因为偶数次的数字都被异或成为0了,最后单独保留了奇数次的数字。
c
🔑 代码实现
//寻找奇数
int main()
{
int n = 0;
while (~scanf("%d", &n))//scanf函数返回的是读入字符的个数,这里1按位取反是0,可理解为没有输入就跳出循环
{
int i = 0;
int num = 0;
//对每个数字进行异或,出现偶数次的就会异或为0了,而奇数次刚好剩下的就是对应数字
for (i = 0; i < n; i++)
{
int temp = 0;
scanf("%d", &temp);
num ^= temp;
}
printf("%d\n", num);
}
return 0;
}
💯运行结果:
5,给出一个整型数组 numbers 和一个目标值 target ,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。
OJ链接【牛客网题号: NC61 两数之和】【难度:简单】
注意:本题只需要找到第一组符合要求的数据下标即可。不需要返回多组
示例:
输入:[3,2,4],6
返回值:[2,3]
说明:因为 2+4=6 ,而 2的下标为2 , 4的下标为3 ,又因为 下标2 < 下标3 ,所以输出[2,3]
- C语言声明定义全局变量请加上static,防止重复定义
💡分析:(复杂度在降低就用到哈希了,日后会把此题拿出来再做)
让我们先来学习下这个函数:
返回两个数组要求函数返回类型为指针。
1,从第0个位置开始一个一个数字找
2,从第一个数字往后的数字中找出另一个数字
3,与numbers[i]相加等于target的数字找到了则i和j就是对应两个数字下标
4,没有符合的下标则返回数组大小为0;
c
🔑 代码实现
//NC61 两数之和
int* twoSum(int* numbers, int numbersLen, int target, int* returnSize)
{
int i = 0;
int j = 0;
*returnSize = 2;
static ret_arr[2] = { 0 };
memset(ret_arr, 0x00, sizeof(ret_arr));//静态空间不会二次初始化,因此手动初始化
for (int i = 0; i < numbersLen; i++)
{//从第0个位置开始一个一个数字找
for (int j = i + 1; j < numbersLen; j++)
{//从第一个数字往后的数字中找出另一个数字
//与numbers[i]相加等于target的数字找到了则i和j就是对应两个数字下标
if (numbers[i] + numbers[j] == target)
{
ret_arr[0] = i + 1;//题目要求下标从1开始
ret_arr[1] = j + 1;
return ret_arr;
}
}
}
*returnSize = 0;//没有符合的下标则返回数组大小为0;
return NULL;
}
六、珠玑妙算游戏(the game of master mind)的玩法如下。
计算机有4个槽,每个槽放一个球,颜色可能是红色( R )、黄色( Y )、绿色( G )或蓝色( B )。例如,计算机可能有 RGGB 4种(槽1为红色,槽2、3为绿色,槽4为蓝色)。作为用户,你试图猜出颜色组合。打个比方,你可能会猜 YRGB 。要是猜对某个槽的颜色,则算一次"猜中";要是只猜对颜色但槽位猜错了,则算一次"伪猜中"。注意,"猜中"不能算入"伪猜中"。
给定一种颜色组合 solution 和一个猜测 guess ,编写一个方法,返回猜中和伪猜中的次数answer ,其中 answer[0]为猜中的次数, answer[1] 为伪猜中的次数。
leetcode链接【 leetcode 题号:面试题 16.15. 珠玑妙算】【难度:简单】
示例:
输入: solution="RGBY",guess="GGRR"
输出: [1,1]
解释: 猜中1次,未猜中1次。
💡分析:
遍历两个数组,统计猜中次数和伪猜中次数
猜中次数:若位置相同且颜色字符也相同在猜中次数计数器+1
伪猜中次数:颜色相同,但是在不同位置,这时候只需要除去猜中位置之外,统计两个数组中各个字符出现的数量,取较小的一方就是每种颜色伪猜中的数量了
c
🔑 代码实现
int* masterMind(char* solution, char* guess, int* returnSize)
{
*returnSize = 2;
static int arr[2] = { 0 };
arr[0] = 0; arr[1] = 0;//静态空间不会进行二次初始化因此每次重新初始化,可以使用memset函数
int s_arr[26] = { 0 };//26个字符位 solution 四种颜色数量统计
int g_arr[26] = { 0 };//26个字符位 guess 四种颜色数量统计
for (int i = 0; i < 4; i++)
{
if (solution[i] == guess[i])
{
arr[0] += 1;//位置和颜色完全一致则猜中数量+1
}
else
{
//统计同一位置不同颜色的两组颜色数量,伪猜中不需要对应位置相同,只需要有对应数量的颜色就行
s_arr[solution[i] - 'A'] += 1; //统计solution对应颜色字符出现次数
g_arr[guess[i] - 'A'] += 1;//统计guess对应颜色字符出现次数
}
}
//在两个颜色数量统计数组中查看颜色数量,取相同位置较小的一方就是为猜中数量
for (int i = 0; i < 26; i++)
{
arr[1] += s_arr[i] > g_arr[i] ? g_arr[i] : s_arr[i];
}
return arr;
}
七,数列的定义如下:数列的第一项为n,以后各项为前一项的平方根,求数列的前m项的和。
🌟输入描述:
输入数据有多组,每组占一行,由两个整数 n(n<10000) 和 m(m<1000) 组成,n和m的含义如前所述。
输出描述:
对于每组输入数据,输出该数列的和,每个测试实例占一行,要求精度保留2位小数。
OJ链接【牛客网题号: ZJ16 数列的和】【难度:简单】
示例:
输入:81 4
2 2
输出:94.73
3.41
💡分析:
利用sqrt()函数求平方根
c
🔑 代码实现
#include<stdio.h>
#include<math.h>
int main()
{
double n = 0.0;
double m = 0.0;
while (scanf("%lf%lf", &n, &m) != EOF)//实现多组循环
{
double sum = 0.00;
int i = 0;
for (i = 0; i < m; i++)
{
sum += n;
n = sqrt(n);
}
printf("%.2lf\n", sum);
}
return 0;
}
💯运行结果:
八,有一只兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子,假如兔子都不死,问第 n 个月的兔子总数为多少?注意:本题有多组数据。
数据范围:每组输入满足 1 <= n <= 31
🌟输入描述:多行输入,一行输入一个int型整数表示第n个月
输出描述:每一行输出对应的兔子总数
OJ:【牛客网题号: HJ37 统计每个月兔子的总数】【难度:简单】
示例:
输入:1 2 3 4 5 6 9
输出:1 1 2 3 5 8 34
💡分析:这道题的关键在于寻找数字之间的规律,如果细心的同学会发现这其实是一个斐波那契数列。第 n 个月的兔子数量实际上就是第 n-1 个斐波那契数。
c
🔑 代码实现
//HJ37 统计每个月兔子的总数
#include<math.h>
int main()
{
int n = 0;
while (~scanf("%d", &n))
{
int num1 = 1;
int num2 = 1;
int ret = 0;
int i = 0;
for (i = 2; i < n; i++)
{
ret = num1 + num2;
num1 = num2; num2 = ret;
}
printf("%d\n", ret);
}
}
💯运行结果:
💘后期会推出更多C语言练习题,希望大家与我共同进步,早日成为大佬!