当前位置: 首页 > news >正文

【C语言16天强化训练】从基础入门到进阶:Day 4


🔥个人主页:艾莉丝努力练剑

❄专栏传送门:《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、洛谷刷题、C/C++基础知识知识强化补充、C/C++干货分享&学习过程记录

🍉学习方向:C/C++方向

⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平

前言:距离我们学完C语言已经过去一段时间了,在学习了初阶的数据结构之后,博主还要更新的内容就是【C语言16天强化训练】,之前博主更新过一个【C语言刷题12天IO强训】的专栏,那个只是从入门到进阶的IO模式真题的训练。【C语言16天强化训练】既有IO型,也有接口型。和前面一样,今天依然是训练五道选择题和两道编程算法题,希望大家能够有所收获!



目录

正文

一、五道选择题

1.1  题目1

1.2  题目2

1.3  题目3

1.4  题目4

1.5  题目5

二、两道算法题

2.1  错误的集合

题目理解:

2.2  密码检查

题目理解:

结尾


正文

一、五道选择题

1.1  题目1

题干:设变量已正确定义,以下不能统计出一行中输入字符个数(不包含回车符)的程序段是()

A.  n=0;while(ch=getchar()!='\n')n++;     B. n=0;while(getchar()!='\n')n++;    

C. for(n=0;getchar()!='\n';n++);               D. n=0;for(ch=getchar();ch!='\n';n++);

解析:

其他选项都没有问题,我们看D选项这里,在for循环的初始化部分,ch=getchar()只执行一次(读取第一个字符),然后循环条件检查 ch!='\n' 。如果第一个字符不是换行符,则进入循环,但循环体内没有语句(只有空语句;),且迭代部分n++执行,但没有再次读取字符。因此,ch始终是第一个字符,如果第一个字符不是换行符,循环将无限执行,因为ch永远不改变,导致无限循环和错误计数。所以,这个选项不能正确统计字符个数。

因此,不能统计一行中输入字符个数(不包含回车符)的选项是D

1.2  题目2

题干:运行以下程序后,如果从键盘上输入 65 14 <回车> ,则输出结果为( )

int main()
{int m, n;printf("Enter m,n;");scanf("%d%d", &m,&n);while (m!=n) //1{while(m>n) m=m-n; //2while(n>m) n=n-m; //3}printf("m=%d\n",m);return 0;
}

A. 3      B. 2     C.  1    D. 0

解析:

我们输入m=65, n=14,<回车>之后——
第一次外层循环(m != n,65 != 14)
进入内层循环1:m>n(65>14),执行m=m-n多次:
第一次:m=65-14=51
第二次:m=51-14=37
第三次:m=37-14=23
第四次:m=23-14=9(现在m=9, n=14,m<n,退出内层循环1)
进入内层循环2:n>m(14>9),执行n=n-m:
第一次:n=14-9=5(现在n=5, m=9,n<m,退出内层循环2)
此时m=9, n=5(不相等),继续外层循环。

第二次外层循环(m != n,9 != 5)
内层循环1:m>n(9>5),执行m=m-n:
第一次:m=9-5=4(现在m=4, n=5,m<n,退出)
内层循环2:n>m(5>4),执行n=n-m:
第一次:n=5-4=1(现在n=1, m=4,n<m,退出)
此时m=4, n=1(不相等),继续外层循环。

第三次外层循环(m != n,4 != 1)
内层循环1:m>n(4>1),执行m=m-n多次:
第一次:m=4-1=3
第二次:m=3-1=2
第三次:m=2-1=1(现在m=1, n=1,m==n,退出内层循环1)
此时m=1, n=1,相等,退出外层循环。

最终输出m=1。

因此,输出结果为1,即选项C

1.3  题目3

题干:若运行以下程序时,从键盘输入 ADescriptor<回车> ,则下面程序的运行结果是( )

#include <stdio.h>
int main()
{char c;int v0=0,v1=0,v2=0;do{switch(c=getchar()){case'a':case'A':case'e':case'E':case'i':case'I':case'o':case'O':case'u':case'U':v1 += 1;default:v0+= 1;v2+=1;}}while(c!='\n');printf("v0=%d,v1=%d,v2=%d\n",v0,v1,v2);return 0;
}

A.  v0=7,v1=4,v2=7     B.  v0=8,v1=4,V2=8     C. v0=11,v1=4,v2=11      D.  v0=12,v1=4,v2=12

解析:

总共处理了12个字符(包括换行符)——

元音有:' A ',' e ',' i ',' o '(共4个),所以 v1 = 4。

每个字符都会执行default,所以 v0 和 v2 都是12。

所以正确答案就是D

1.4  题目4

题干:如下函数是求两个int数字最大公约数的,指出其中存在的问题【多选】( )

int gcd(char x,char y)
{int min = x < y ? x : y;for (min = 0; min > 0; min--)if (x % min = 0 && y % min = 0)return min;
}

A. 参数类型不对    B. 循环变量min初值不对    C. 判断等于的符号不对    D. 返回类型不对

解析:

A选项——参数类型不对:函数目的是求两个整数的最大公约数,但参数类型为char(字符类型),而不是int(整数类型)。虽然char可以视为小整数,但通常最大公约数函数应使用int类型,以处理更大的数字和通用整数。因此,参数类型不正确的确是其存在的问题。

B选项——循环变量min初值不对:在循环中,min被初始化为 0(for(min = 0; ...)),但循环条件为min > 0,因此循环根本不会执行(因为初始值0不满足min>0)。正确的做法是使用之前计算的 min(即 x 和 y 中的较小值)作为初始值,然后递减。但这里覆盖了之前的值,导致逻辑错误。

C选项——判断等于的符号不对:在条件判断中,if (x % min = 0 && y % min = 0) 使用了赋值运算符 = 而不是相等比较运算符 == 。这会导致编译错误(因为赋值操作不允许在条件中这样使用)或逻辑错误(总是将0赋值给表达式)。正确的应该是 ==。

D选项——返回类型不对:函数返回类型是 int,这本身是合适的,因为最大公约数是整数。但问题在于函数可能没有返回任何值(如果循环没有执行,则没有返回值),这会导致未定义行为。不过,返回类型 int 本身并不是错误,但函数设计有缺陷。

因此,所有选项A、B、C都是正确的问题描述。D选项(返回类型不对)可能不是主要问题,但函数确实存在返回类型与逻辑不匹配的风险(可能无返回值)。严格来说,D也是问题之一(因为函数可能无法返回正确结果)。

但根据题干“指出其中存在的问题【多选】”,A、B、C是明显错误,D也有问题。

综上所述,正确答案就是ABCD。

1.5  题目5

题干:执行下面的程序段,语句3的执行次数为( )

for(i = 0; i <= n-1; i++) // (1)for(j = n; j > i; j--) // (2)state; // (3)

A. n(n+2)/2     B. (n-1)(n+2)/2     C. n(n+1)/2     D. (n-1)(n+2)

解析:

我们先来分析一下这个嵌套循环——

外层循环:i 从 0 到 n-1(共 n 次迭代)。

内层循环:j 从 n 向下到 i+1(包括),因此内层循环次数为 n - i(因为 j 从 n 到 i+1,步长为1,次数为 n - i)。

语句(3)的执行次数是内层循环的总次数,即对每个 i,内层循环执行 n - i 次。

总次数的计算过程如下所示——

正确选项是C. n(n+1)/2 。

选择题答案如下:

1.1  D

1.2  C

1.3  D

1.4  ABCD

1.5  C

校对一下,大家都做对了吗?

二、两道算法题

2.1  错误的集合

前面我们都是牛客网的题目,今天终于有一道力扣题目了!

力扣题目链接:645. 错误的集合​​​​​​

力扣题解链接:解决【错误的集合】问题

题目描述:

题目理解:

我们需要去找出重复的数字和丢失的数字,可以用计数数组。

这道题是接口型的,下面是C语言的模版(如果是IO型就可以不用管它们了)——

代码演示:

/*** Note: The returned array must be malloced, assume caller calls free().*/
int* findErrorNums(int* nums, int numsSize, int* returnSize) {// 创建计数数组,初始化为0int* count = (int*)calloc(numsSize + 1, sizeof(int));int* result = (int*)malloc(2 * sizeof(int));*returnSize = 2;// 统计每个数字出现的次数for (int i = 0; i < numsSize; i++) {count[nums[i]]++;}// 找出重复的数字和丢失的数字for (int i = 1; i <= numsSize; i++) {if (count[i] == 2) {result[0] = i; // 重复的数字}if (count[i] == 0) {result[1] = i; // 丢失的数字}}free(count);return result;
}

时间复杂度O(n)

空间复杂度O(n)

我们可以改进一下,优化复杂度——

int* findErrorNums(int* nums, int numsSize, int* returnSize) {int* result = (int*)malloc(2 * sizeof(int));*returnSize = 2;long long n = numsSize;long long sum = n * (n + 1) / 2;long long sum_sq = n * (n + 1) * (2 * n + 1) / 6;long long actual_sum = 0;long long actual_sum_sq = 0;for (int i = 0; i < numsSize; i++) {actual_sum += nums[i];actual_sum_sq += (long long)nums[i] * nums[i];}// sum - actual_sum = missing - duplicate// sum_sq - actual_sum_sq = missing^2 - duplicate^2long long diff = sum - actual_sum;        // missing - duplicatelong long diff_sq = sum_sq - actual_sum_sq; // missing^2 - duplicate^2// missing + duplicate = diff_sq / difflong long sum_md = diff_sq / diff;result[1] = (diff + sum_md) / 2; // missing numberresult[0] = sum_md - result[1];  // duplicate numberreturn result;
}

时间复杂度O(n)

空间复杂度O(1)

我们学习了C++之后也可以尝试用C++来实现一下,看看自己前段时间C++学得怎么样——

用计数数组实现的代码演示:

class Solution {
public:vector<int> findErrorNums(vector<int>& nums) {int n = nums.size();vector<int> count(n + 1, 0);vector<int> result(2);// 统计每个数字出现的次数for (int num : nums) {count[num]++;}// 找出重复的数字和丢失的数字for (int i = 1; i <= n; i++) {if (count[i] == 2) {result[0] = i; // 重复的数字}if (count[i] == 0) {result[1] = i; // 丢失的数字}}return result;}
};

时间复杂度:O(n),空间复杂度:O(n)

我们还可以对空间复杂度进行一下优化——

class Solution {
public:vector<int> findErrorNums(vector<int>& nums) {int n = nums.size();long long sum = (long long)n * (n + 1) / 2;long long sum_sq = (long long)n * (n + 1) * (2 * n + 1) / 6;long long actual_sum = 0;long long actual_sum_sq = 0;for (int num : nums) {actual_sum += num;actual_sum_sq += (long long)num * num;}long long diff = sum - actual_sum;        // missing - duplicatelong long diff_sq = sum_sq - actual_sum_sq; // missing² - duplicate²long long sum_md = diff_sq / diff;        // missing + duplicateint missing = (diff + sum_md) / 2;int duplicate = sum_md - missing;return {duplicate, missing};}
};

时间复杂度:O(n),空间复杂度:O(1)

我们目前要写出来C++的写法是非常考验前面C++的学习情况,大家可以尝试去写一写,优先掌握C语言的写法,博主还没有介绍C++的算法题,之后会涉及的,敬请期待

2.2  密码检查

题目链接:REAL585 密码检查

题目描述:

题目理解:

我们将编写一个C程序来逐个检查每个密码,并输出"YES"或"NO"。

由题意可知,密码必须满足以下条件:

1、密码只能由大写字母、小写字母和数字构成;

2、密码不能以数字开头;

3、密码至少包含大写字母、小写字母和数字中的两种类型;

4、密码长度至少为8。

这道题是IO型的,下面是C语言的模版(如果是IO型就可以不用管它们了)——

代码演示:

#include <stdio.h>
#include <ctype.h>
#include <string.h>int main() 
{int n;scanf("%d", &n);while (getchar() != '\n'); // 清空输入缓冲区for (int i = 0; i < n; i++) {char password[101];if (fgets(password, sizeof(password), stdin) == NULL) {printf("NO\n");continue;}// 移除换行符和可能的回车符int len = strlen(password);while (len > 0 && (password[len - 1] == '\n' || password[len - 1] == '\r')) {password[len - 1] = '\0';len--;}// 检查是否为空字符串if (len == 0) {printf("NO\n");continue;}int has_upper = 0, has_lower = 0, has_digit = 0;int valid = 1;// 条件4: 长度至少为8if (len < 8) {valid = 0;}// 条件2: 不能以数字开头if (isdigit(password[0])) {valid = 0;}// 检查每个字符for (int j = 0; j < len; j++) {unsigned char c = password[j]; // 使用unsigned char避免符号扩展问题if (isupper(c)) {has_upper = 1;} else if (islower(c)) {has_lower = 1;} else if (isdigit(c)) {has_digit = 1;} else {valid = 0;break;}}// 条件3: 至少包含两种类型if (valid) {int type_count = has_upper + has_lower + has_digit;if (type_count < 2) {valid = 0;}}printf("%s\n", valid ? "YES" : "NO");}return 0;
}

时间复杂度O(n*m)

空间复杂度O(m)

这个程序存在一定的问题,测试用例只能通过两个。博主会把最终代码实现呈现在下面——

时间复杂度O(n*m)

空间复杂度O(m)

我们学习了C++之后也可以尝试用C++来实现一下,看看自己前段时间C++学得怎么样——

代码演示:

#include <iostream>
#include <string>
#include <cctype>
using namespace std;bool isValidPassword(const string& password) {// 检查长度if (password.length() < 8) {return false;}// 检查不能以数字开头if (isdigit(password[0])) {return false;}bool hasUpper = false;bool hasLower = false;bool hasDigit = false;for (char c : password) {// 检查字符类型if (isupper(c)) {hasUpper = true;} else if (islower(c)) {hasLower = true;} else if (isdigit(c)) {hasDigit = true;} else {// 包含非法字符return false;}}// 检查至少包含两种类型int typeCount = (hasUpper ? 1 : 0) + (hasLower ? 1 : 0) + (hasDigit ? 1 : 0);return typeCount >= 2;
}int main() 
{int n;cin >> n;cin.ignore(); // 消耗换行符for (int i = 0; i < n; i++) {string password;getline(cin, password);if (isValidPassword(password)) {cout << "YES" << endl;} else {cout << "NO" << endl;}}return 0;
}

时间复杂度:O(n*m),空间复杂度:O(m)

我们目前要写出来C++的写法是非常考验前面C++的学习情况,大家可以尝试去写一写,优先掌握C语言的写法,博主还没有介绍C++的算法题,之后会涉及的,敬请期待


结尾

本文内容到这里就全部结束了,希望大家练习一下这几道题目,这些基础题最好完全掌握!

往期回顾:

【C语言16天强化训练】从基础入门到进阶:Day 3

【C语言16天强化训练】从基础入门到进阶:Day 2

【C语言16天强化训练】从基础入门到进阶:Day 1

结语:感谢大家的阅读,记得给博主“一键四连”,感谢友友们的支持和鼓励!

http://www.dtcms.com/a/340773.html

相关文章:

  • K8S-Pod资源对象——Pod探针
  • 基于深度学习CenterPoint的3D目标检测部署实战
  • MySQL的简单介绍
  • PyTorch API 5
  • 通过uniapp将vite vue3项目打包为android系统的.apk包,并实现可自动升级功能
  • PyTorch API 7
  • PiscCode集成Hand Landmarker:实现高精度手部姿态检测与分析
  • 查看文件内容
  • kotlin 协程笔记
  • 手机 浏览器调用摄像头扫描二维码Quagga
  • RAG系统文本检索优化:Cross-Encoder与Bi-Encoder架构技术对比与选择指南
  • 时序数据库IoTDB的列式存储引擎
  • 5G-A赋能AR眼镜:毫米级虚实融合的未来已来
  • Kubernetes 负载均衡现象解析:为何同一批次请求集中于单个 Pod
  • 小红书账号隔离:解决IP关联问题方案
  • AI 创业公司分析报告:RealRoots
  • 结合SAT-3D,运动+饮食双重养腰新方式
  • 3ds Max 流体模拟终极指南:从创建到渲染,打造真实液体效果
  • MySQL InnoDB事务acid特性的原理和隔离级别的实现原理
  • 机器学习——附录与补充
  • 【007TG洞察】Bitget全球快闪店活动解析:Web3项目如何实现高效用户增长
  • ios八股文 -- Objective-c
  • Java EE ----- Spring Boot 日志
  • 【JavaEE】(17) MyBatis 基础
  • 【JavaEE】多线程(线程安全问题)
  • k8sday12数据存储(1/2)
  • 【表的操作】
  • 开源大模型如何选择?GPT-OSS综合评估
  • HTML--pre标签的作用
  • 决策树1.2