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

发布于:2025-08-29 ⋅ 阅读:(19) ⋅ 点赞:(0)


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

❄专栏传送门:《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

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


网站公告

今日签到

点亮在社区的每一天
去签到