
❄专栏传送门:《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.1 题目1)
[1.2 题目2](#1.2 题目2)
[1.3 题目3](#1.3 题目3)
[1.4 题目4](#1.4 题目4)
[1.5 题目5](#1.5 题目5)
[2.1 最大连续 1 的个数](#2.1 最大连续 1 的个数)
[2.1.1 题目理解](#2.1.1 题目理解)
[2.1.2 思路](#2.1.2 思路)
[2.2 完全数计算](#2.2 完全数计算)
[2.2.1 题目理解](#2.2.1 题目理解)
[2.2.2 思路](#2.2.2 思路)
[2.2.3 更通用的实现(如果需要验证其他数字)](#2.2.3 更通用的实现(如果需要验证其他数字))
[2.2.4 两种方法的比较:](#2.2.4 两种方法的比较:)
一、五道选择题
1.1 题目1
**题干:**声明以下变量,则表达式: ch / i + (f * d -- i) 的结果类型为( )
cpp
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
**题干:**关于代码的说法正确的是( )
cpp
#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语言语法的表达式是( )
cpp
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
**题干:**下面函数的输出结果是( )
cpp
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
**题干:**如下代码的输出结果是( )
cpp
#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时检查是否需要更新最大值。
代码演示:
cpp
//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++学得怎么样------

代码演示:
cpp
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型就可以不用管它们了)------

代码演示:
cpp
//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++学得怎么样------

代码演示:
cpp
//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 更通用的实现(如果需要验证其他数字)
如果题目要求验证其他数字是否为完全数,可以使用以下更通用的方法:
cpp
//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++的算法题,之后会涉及的,敬请期待!
结尾
本文内容到这里就全部结束了,希望大家练习一下这几道题目,这些基础题最好完全掌握!
往期回顾:
结语: 感谢大家的阅读,记得给博主"一键四连",感谢友友们的支持和鼓励!