【C语言16天强化训练】从基础入门到进阶:Day 11
🔥个人主页:艾莉丝努力练剑
❄专栏传送门:《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 最大连续 1 的个数
2.1.1 题目理解
2.1.2 思路
2.2 完全数计算
2.2.1 题目理解
2.2.2 思路
2.2.3 更通用的实现(如果需要验证其他数字)
2.2.4 两种方法的比较:
结尾
一、五道选择题
1.1 题目1
题干:声明以下变量,则表达式: ch / i + (f * d – i) 的结果类型为( )
char ch;
int i;
float f;
double d;
A. char B. int C. float D. double
解析:正确答案就是D。
A选项:ch / i:char 和 int 运算,char 提升为 int,结果为 int。
B选项:f * d:float 和 double 运算,float 提升为 double,结果为 double。
C选项:(f * d – i):double 和 int 运算,int 提升为 double,结果为 double。
D选项:ch / i + (f * d – i) :int 和 double 运算,int 提升为 double,最终结果为 double。
1.2 题目2
题干:关于代码的说法正确的是( )
#include <stdio.h>
int main()
{int x = -1;unsigned int y = 2;if (x > y){printf("x is greater");} else{printf("y is greater");} return 0;
}
A. x is greater B. y is greater C. 依赖实现 D. 随机
解析:正确答案就是A。
(1)x是负数(-1),y是无符号整数(2);
(2)当有符号与无符号比较时,有符号数会被转换为无符号数(即 -1 转换为非常大的正数,因为补码表示)。
因此 x > y
为真(-1 转换为无符号是 0xFFFFFFFF,即 4294967295 > 2)。
1.3 题目3
题干:已知有如下各变量的类型说明,则以下不符合C语言语法的表达式是( )
int k, a, b;
unsigned int w = 5;
double x = 1.42;
A. x%3 B. w += -20 C. k = (a = 200 , b = 300) D. a += a -= a = 9
解析:正确答案就是A。
A. x % 3:取模运算 % 只能用于整数类型,double 不能取模(编译错误)。
B. w += -20:合法(相当于 w += (-20))。
C. k = (a = 200 , b = 300) :逗号表达式,合法(k 被赋值为 300)。
D. a += a -= a = 9:虽然多次赋值,但语法允许(从右到左:a = 9,然后 a -= a 是0,最后a += a得到0),因为赋值运算符是右结合的,这里就相当于a += (a -= (a = 9))。
1.4 题目4
题干:下面函数的输出结果是( )
void func()
{int k = 1^(1 << 31 >> 31);printf("%d\n", k);
}
A. 0 B. -1 C. -2 D. 1
解析:正确答案就是C。
(1)1 << 31:将1左移31位(假设32位int),得到 0x80000000(即 -2147483648,最高位为1表示负数)。
(2)1 << 31 >> 31:算术右移31位(符号位扩展),所有位都变为与符号位相同(即全1),得到 0xFFFFFFFF(即 -1)。
(3)1 ^ ( - 1 ):异或运算(1 和 -1 的二进制每一位都相反),结果为 0xFFFFFFFE(即 -2)。
1.5 题目5
题干:如下代码的输出结果是( )
#include <stdio.h>
int main()
{int i = 1;sizeof(i++);printf("%d\n", i);return 0;
}
A. 1 B. 4 C. 2 D. 8
解析:正确答案就是A。
(1)sizeof 是编译时运算符,不会对操作数求值(i++不会执行)。
(2)因此 i 的值保持不变,输出1。
选择题答案如下:
1.1 D
1.2 A
1.3 A
1.4 C
1.5 A
校对一下,大家都做对了吗?
二、两道算法题
2.1 最大连续 1 的个数
力扣链接:485. 最大连续 1 的个数
力扣题解链接:线性扫描解决【最大连续1】问题
题目描述:
2.1.1 题目理解
1、二进制数组特性:数组元素只能是0或1,这个限制条件实际上简化了问题;
2、连续性要求:我们需要的是连续的1,中间不能有0间隔;
3、最大值寻找:不是统计所有1的个数,而是找出最长的连续1序列。
这道题是接口型的,下面是C语言的模版(如果是IO型就可以不用管它们了)——
2.1.2 思路
1、maxCount: 记录历史最大连续1的个数;
2、currentCount: 记录当前连续1的个数;
3、遍历数组,遇到1就增加计数,遇到0就重置计数;
4、每次遇到1时检查是否需要更新最大值。
代码演示:
//C语言实现——线性扫描方法
int findMaxConsecutiveOnes(int* nums, int numsSize) {int maxCount = 0;int currentCount = 0;for (int i = 0; i < numsSize; i++) {if (nums[i] == 1){currentCount++;maxCount = currentCount > maxCount ? currentCount : maxCount;}else {currentCount = 0;}}return maxCount;
}
时间复杂度:O(n);
空间复杂度:O(1)。
我们学习了C++之后也可以尝试用C++来实现一下,看看自己前段时间C++学得怎么样——
代码演示:
class Solution {
public:int findMaxConsecutiveOnes(vector<int>& nums) {int maxCount = 0;int currentCount = 0;for (int num : nums) {if (num == 1) {currentCount++;maxCount = max(maxCount, currentCount);}else {currentCount = 0;}}return maxCount;}
};
时间复杂度:O(n),空间复杂度:O(1)。
我们目前要写出来C++的写法是非常考验前面C++的学习情况好不好的,大家可以尝试去写一写,优先掌握C语言的写法,博主还没有介绍C++的算法题,之后会涉及的,敬请期待!
2.2 完全数计算
牛客网链接:HJ56 完全数计算
题目描述:
2.2.1 题目理解
我们需要计算1到n之间完全数的个数。已知完全数的定义是:它所有的真因子(除了自身以外的约数)之和等于它本身。
2.2.2 思路
1、问题分析:我们需要找出1到n之间的所有完全数。已知的完全数很少,在n最大为500,000的情况下,可以预先知道可能的完全数。
2、关键点:完全数非常稀少,在给定的范围内(n ≤ 500,000)只有几个完全数(6, 28, 496, 8128等)。但8128大于500,000?实际上500,000 > 8128,所以范围内有4个?但题目示例输入1000输出3(6,28,496),因为8128大于1000。但n最大500,000,8128 < 500,000,所以实际上有4个?但496 < 1000, 8128 > 1000?注意n最大500,000,所以8128(小于500,000)应该包括?但题目示例输入1000输出3,说明1000以内有3个(6,28,496),而500,000以内还有8128。
3、优化思路:由于完全数很少,可以直接检查已知的完全数是否在1到n之间。已知的完全数有6, 28, 496, 8128。下一个完全数是33550336,但远大于500,000,所以无需考虑。
4、算法选择:因此,只需要判断n是否大于等于6、28、496、8128,然后计数即可。
这道题是IO型的,下面是C语言的模版(如果是IO型就可以不用管它们了)——
代码演示:
//C语言实现
#include <stdio.h>int main()
{int n;scanf("%d", &n);int count = 0;if (n >= 6) count++;if (n >= 28) count++;if (n >= 496) count++;if (n >= 8128) count++;printf("%d\n", count);return 0;
}
时间复杂度:O(1);
空间复杂度:O(1)。
1、输入处理:读取整数n。
2、完全数检查:检查n是否大于等于已知的完全数(6, 28, 496, 8128)。每满足一个条件,计数增加。
3、输出结果:打印完全数的个数。
这种方法利用了完全数的稀少性,直接进行条件判断,简单高效。
我们学习了C++之后也可以尝试用C++来实现一下,看看自己前段时间C++学得怎么样——
代码演示:
//C++实现
#include <iostream>
using namespace std;int main()
{int n;cin >> n;int count = 0;if (n >= 6)count++;if (n >= 28)count++;if (n >= 496)count++;if (n >= 8128)count++;cout << count << endl;return 0;
}
时间复杂度:O(1),空间复杂度:O(1)。
1、输入处理:使用cin读取整数n。
2、完全数检查:通过一系列条件判断来统计完全数的个数。
(1)如果n ≥ 6,计数+1(包含完全数6);
(2)如果n ≥ 28,计数+1(包含完全数28);
(3)如果n ≥ 496,计数+1(包含完全数496);
(4)如果n ≥ 8128,计数+1(包含完全数8128)。
3、输出结果:使用cout输出完全数的个数。
2.2.3 更通用的实现(如果需要验证其他数字)
如果题目要求验证其他数字是否为完全数,可以使用以下更通用的方法:
//C++实现——更通用的实现(如果需要验证其他数字)
#include <iostream>
#include <cmath>
using namespace std;bool isPerfectNumber(int num)
{if (num <= 1) return false;int sum = 1; // 1是所有数的真因子int sqrt_num = sqrt(num);for (int i = 2; i <= sqrt_num; i++) {if (num % i == 0) {sum += i;if (i != num / i) {sum += num / i;}}}return sum == num;
}int main()
{int n;cin >> n;int count = 0;// 直接检查已知的完全数(更高效)if (n >= 6) count++;if (n >= 28) count++;if (n >= 496) count++;if (n >= 8128) count++;cout << count << endl;return 0;// 如果需要验证所有数字(效率较低,但更通用)/*for (int i = 2; i <= n; i++) {if (isPerfectNumber(i)) {count++;}}cout << count << endl;return 0;*/
}
时间复杂度:O(1),空间复杂度:O(1)。
2.2.4 两种方法的比较
1、直接判断法:利用已知完全数稀少的特性,直接进行条件判断,时间复杂度O(1),是最优解。
2、通用验证法:
可以验证任意数字是否为完全数,但时间复杂度较高,对于n=500,000的情况可能会超时。
对于本题,推荐使用第一种直接判断法,因为它既简单又高效。
我们目前要写出来C++的写法是非常考验前面C++的学习情况好不好的,大家可以尝试去写一写,优先掌握C语言的写法,博主还没有介绍C++的算法题,之后会涉及的,敬请期待!
结尾
本文内容到这里就全部结束了,希望大家练习一下这几道题目,这些基础题最好完全掌握!
往期回顾:
【C语言16天强化训练】从基础入门到进阶:Day 10
【C语言16天强化训练】从基础入门到进阶:Day 9
【C语言16天强化训练】从基础入门到进阶:Day 8
【C语言16天强化训练】从基础入门到进阶:Day 7
【C语言16天强化训练】从基础入门到进阶:Day 6
【C语言16天强化训练】从基础入门到进阶:Day 5
【C语言16天强化训练】从基础入门到进阶:Day 4
【C语言16天强化训练】从基础入门到进阶:Day 3
【C语言16天强化训练】从基础入门到进阶:Day 2
【C语言16天强化训练】从基础入门到进阶:Day 1
结语:感谢大家的阅读,记得给博主“一键四连”,感谢友友们的支持和鼓励!