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


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

❄专栏传送门:《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 数字颠倒](#2.1 数字颠倒)

[2.1.1 题目理解](#2.1.1 题目理解)

[2.1.2 思路](#2.1.2 思路)

[2.1.3 实现(C/C++)](#2.1.3 实现(C/C++))

[2.2 单词倒排](#2.2 单词倒排)

[2.2.1 题目理解](#2.2.1 题目理解)

[2.2.2 思路](#2.2.2 思路)

[2.2.3 实现(C/C++)](#2.2.3 实现(C/C++))

结尾


一、五道选择题

1.1 题目1

**题干:**请阅读以下程序,其运行结果是( )

cpp 复制代码
int main()
{
    char c='A';
    if('0'<=c<='9') printf("YES");
    else printf("NO");
    return 0;
}

A. YES B. NO C. YESNO D. 语句错误

解析:正确答案就是A选项。

'0'<=c<='9'并非判断x大于等于字符0,小于等于字符9,而是先执行'0'<=c,使用这个表达式的结果再和'9'比较,'0'的ASCII码值是48,'A'的ASCII码值是'65',故'0'<c是真值1,1无疑是小于字符'9'的,最终是真,即选项A"YES"。

1.2 题目2

**题干:**假设编译器规定 int 和 short 类型长度分别为32位和16位,若有下列C语言语句,则 y 的机器数为( )

cpp 复制代码
unsigned short x = 65530;
unsigned int y = x;

A. 0000 7FFA B. 0000 FFFA C. FFFF 7FFA D. FFFF FFFA

解析:正确答案就是B选项。

unsigned short类型的x变量2个字节保存了65530,十六进制形式为0xFFFA,x给y赋值时会整型提升,而无符号数在提升时高位补0,其实就相当于把x的值放在了y的低2个字节的空间中,故选B。

1.3 题目3

**题干:**下列程序的输出结果是什么( )

cpp 复制代码
#include<stdio.h>
int main()
{
    int n = 1001;
    int ans = 0;
    for(int i = 1; i <= n; ++i)
    {
        ans ^= i % 3;
    }
    printf("%d",ans);
    return 0;
}

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

解析:正确答案就是B选项。

可以这样解释:

i % 3 的值按1、2、0循环,可推算出ans按1、3、3、2、0、0循环,循环进行1001次,而1001%6=5,也就是ans按规律得到的第5个数为最终结果,故ans=0。

也可以这样解释:

循环计算1001次 i % 3 的异或。i % 3 的值每3次循环(0,1,2)重复,异或结果:0^1^2=3(二进制11,即3),但每3次重复。1001/3=333组余2(最后余i=1000和1001:1000%3=1,1001%3=2)。
每组3次异或结果为3(但ans初始0),每组的异或值:0^1^2=3,但连续异或333组:由于3的二进制为11,异或多次时,取决于次数。
实际上,每两组异或会抵消:3^3=0,所以333组(奇数组)异或后为3,再异或最后两个(1和2):3^1^2=0(因为3^1=2, 2^2=0)。
因此最终ans=0。

1.4 题目4

**题干:**C语言中,下列运算符优先级最高的是 ( )

A. ! B. % C. >> D. ==

解析:正确答案就是A选项。

单目运算符的优先级通常都比较高,具体情况可查阅运算符优先级表格。

运算符优先级:

!(逻辑非)优先级最高(单目运算符),

%(取模)和 >>(右移)为算术运算符,优先级次之,

==(相等)优先级较低。
因此优先级最高的是 !

1.5 题目5

**题干:**要使 a 的低四位翻转,需要进行操作是( )

A. a | 0xF B. a & 0xF C. a ^ 0xF D. ~a

解析:正确答案就是C选项。

十六进制数0xF是4位1,参与运算时整型提升,高位都是0。低四位和1异或,0^1是1,1^1是0;高位和0异或,0^0是0,1^0是1。故而可以通过异或F使得a的低四位翻转,并保持高位不变。

也可以这样解释:

要使低四位翻转(即0变1,1变0),应使用异或操作:a ^ 0xF (0xF二进制为00001111,异或后低四位取反,高位不变)。

其他:

a | 0xF 低四位置1,a & 0xF 只保留低四位,~a 所有位取反。

选择题答案如下:

1.1 A

1.2 B

1.3 B

1.4 A

1.5 C

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


二、两道算法题

2.1 数字颠倒

牛客网链接:HJ11 数字颠倒

题目描述:

2.1.1 题目理解

为了解决这个问题,我们需要将给定的非负整数颠倒后以字符串形式输出,包括任何前导零。关键在于如何处理数字的每一位,并确保颠倒后的字符串正确表示原数字的逆序。

2.1.2 思路

**1、**问题分析 :输入是一个非负整数,需要将其数字顺序颠倒后输出。

例如,输入1516000应输出0006151。

**2、**关键点 :直接使用数学运算逐位提取数字,从最低位开始输出,这样可以自然形成颠倒后的字符串,包括前导零。

**3、**算法选择 :通过循环取模运算获取最后一位数字,并将其转换为字符输出,然后通过整数除法移除已处理的数字。重复此过程直到所有数字处理完毕。

**4、**复杂度分析 :该算法的时间复杂度为O(d),其中d是数字的位数,因为每个数字处理一次。空间复杂度为O(1),仅使用固定空间。

2.1.3 实现(C/C++)

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

代码演示:

cpp 复制代码
//C语言实现
#include <stdio.h>

int main()
{
    int n;
    scanf("%d", &n);
    if (n == 0)
    {
        printf("0");
    }
    else
    {
        while (n)
        {
            printf("%c", '0' + n % 10);
            n /= 10;
        }
    }
    return 0;
}

时间复杂度O(n)

空间复杂度O(1)
**1、**输入处理 :读取输入的整数n。

**2、**特殊情况处理 :如果n为0,直接输出"0"。

**3、**数字颠倒 :对于非零的n,通过循环每次取n的最后一位数字(使用取模运算),转换为对应的字符并输出。随后通过整数除法移除已处理的数字。

**4、**输出结果 :循环直到所有数字处理完毕,输出的字符串即为颠倒后的数字,包括任何前导零。

这种方法高效且直接,确保了正确性和简洁性。

当然还有比这个更加简洁的写法:do while------

代码演示:

cpp 复制代码
//C语言实现------方法2
#include <stdio.h>
int main()
{
    int a;
    scanf("%d", &a);
    do {
        printf("%d", a % 10);
        a /= 10;
    } while (a);
    return 0;
}

时间复杂度O(n)

空间复杂度O(1)

当然还有一种写法:

代码演示:

cpp 复制代码
//C语言实现------方法3
#include <stdio.h>
int main()
{
    int num;
    while (~scanf("%d", &num)) 
    {
        if (num == 0) 
        {
            //0的情况特殊处理,因为0不会进入while循环计算余数,因此不会被打印
            printf("%d", num % 10);
            continue;
        } 
            while(num > 0) 
        {
            printf("%d", num % 10);
            //打印一个数字的个位数 129 % 10 得到9
            num /= 10;
            //通过除以10的方式去掉个位数 例如:129/10 得到12
        }
        printf("\n");
    } 
    return 0;
}

时间复杂度O(n)

空间复杂度O(1)

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

代码演示:

cpp 复制代码
//C++实现
#include <iostream>
using namespace std;

int main()
{
    int n;
    cin >> n;
    if (n == 0)
    {
        cout << '0';
    }
    else
    {
        while (n)
        {
            cout << char('0' + n % 10);
            n /= 10;
        }
    }
    return 0;
}

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

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

2.2 单词倒排

牛客网链接:HJ31 单词倒排

题目描述:

2.2.1 题目理解

我们需要将输入字符串中的单词(仅由大小写字母组成)提取出来,然后逆序输出,单词之间用单个空格分隔。非字母字符作为分隔符。

2.2.2 思路

**1、**读取输入 :使用getline(C++)或fgets(C)读取整行输入。

**2、**提取单词 :遍历字符串中的每个字符,如果是字母则添加到当前单词,否则结束当前单词(如果非空)并添加到单词列表。

**3、**处理最后一个单词 :在遍历结束后,检查是否还有未添加的单词。

**4、**逆序输出 :从单词列表的末尾开始向前输出,单词之间用空格分隔。

这种方法确保了单词的正确提取和逆序输出,同时处理了各种非字母分隔符的情况。

2.2.3 实现(C/C++)

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

代码演示:

cpp 复制代码
//C语言实现
#include <stdio.h>
#include <ctype.h>
#include <string.h>

int main()
{
    char s[10001]; // 总字符长度不超过10^4
    fgets(s, sizeof(s), stdin);
    char words[5000][21]; // 假设最多5000个单词,每个单词最长20
    int count = 0;
    int idx = 0;
    int len = strlen(s);

    for (int i = 0; i < len; i++)
    {
        if (isalpha(s[i]))
        {
            // 将字母添加到当前单词
            words[count][idx++] = s[i];
        }
        else
        {
            if (idx > 0)
            {
                words[count][idx] = '\0'; // 结束当前单词
                count++;
                idx = 0;
            }
        }
    }
    if (idx > 0)
    { // 处理最后一个单词
        words[count][idx] = '\0';
        count++;
    }

    // 逆序输出单词
    for (int i = count - 1; i >= 0; i--)
    {
        printf("%s", words[i]);
        if (i > 0) printf(" ");
    }
    printf("\n");

    return 0;
}

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

这个的代码量还是很大的,可以再简洁一点------

代码演示:

cpp 复制代码
//C语言实现------方法2
#include <stdio.h>
#include <string.h>
int main() 
{
    char str[10001] = { 0 };
    //题目要求:字符串最长10000
    int row = 0;
    while (gets(str) > 0) 
    {
        char* ptr = str;
        char* word[10000] = { NULL };
        while (*ptr != '\0') 
        {
            //如果是个字母字符,则是单词的起始字符
            if (('z' >= *ptr && *ptr >= 'a') || ('Z' >= *ptr && *ptr >= 'A')) 
            {
                word[row++] = ptr;//保存每个单词的起始地址
                //把本次的单词字母字符走完,直到遇到非字母字符
                while (*ptr != '\0' &&
                    (('z' >= *ptr && *ptr >= 'a') || ('Z' >= *ptr && *ptr >= 'A'))) 
                {
                    ptr++;
                }
                continue;
                //不能继续向下,因为下面的ptr++会跳过当前的非字母字符
            }
            *ptr = '\0';
            //把非字母的数据全部替换为结尾标志
            ptr++;
        }
        for (int i = row - 1; i >= 0; i--) 
        {
            printf("%s ",
                word[i]);
            //针对所有单词的起始地址逆序打印即可
        }
        printf("\n");
    }
}

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

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

代码演示:

cpp 复制代码
//C++实现
#include <iostream>
#include <vector>
#include <string>
#include <cctype>
using namespace std;

int main()
{
    string s;
    getline(cin, s); // 读取整行输入
    vector<string> words;
    string word;

    for (char c : s)
    {
        if (isalpha(c))
        { // 如果是字母,添加到当前单词
            word += c;
        }
        else
        {
            if (!word.empty())
            { // 遇到非字母字符,且当前单词非空,则添加到列表
                words.push_back(word);
                word.clear();
            }
        }
    }
    if (!word.empty())
    { // 处理最后一个单词
        words.push_back(word);
    }

    // 逆序输出单词
    for (int i = words.size() - 1; i >= 0; --i)
    {
        cout << words[i];
        if (i > 0) cout << " ";
    }
    cout << endl;

    return 0;
}

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

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


结尾

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

往期回顾:

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

【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

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