华为OD机试 - 谁没交卷(Python/JS/C/C++ 新系统 100分)

在这里插入图片描述

华为OD机试 新系统 统一考试题库清单(持续收录中)以及考点说明(Python/JS/C/C++)

专栏导读

本专栏收录于《华为OD机试真题(Python/JS/C/C++)》

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。

一、题目描述

张老师组织了一场线上模拟考试,并要求考生使用学号登录网站进行考试。考试完成后张老师发现试卷提交不全,他需要找到哪些同学没有交卷。

若班级内有 N 个学生,则学号从 1 开始到 N 结束,每个学生一个学号。一个班级内学生个数不超过 80,即 0 < N ≤ 80 0 < N \le 80 0<N80

请你编写一个程序,帮助张老师快速找到哪些学号的学生没有交卷。

二、输入描述

  • 班级内学生数量。

  • 交卷学生的学号列表,由于是按照交卷时间排序的,学号是乱序的,同时本题确保学号是合法的,不存在小于 1 或大于 N 的学号。

三、输出描述

  • 未交卷学生的学号列表,按照学号升序排列。

四、测试用例

测试用例1:

1、输入

10
1,5,3,2,6,7,8,9,10

2、输出

4

3、说明

1、2、3、5、6、7、8、9、10 都已经交卷,所以只有 4 号未交卷。

测试用例2:

1、输入

10
9,2,3,5,6,7

2、输出

1,4,8,10

3、说明

已经交卷的是 2、3、5、6、7、9,因此未交卷的是 1、4、8、10。

五、解题思路

学生学号一定是 1 ~ N,而 N <= 80,非常适合使用一个布尔数组记录每个学生是否已经交卷。

例如 N = 10:

学号       1  2  3  4  5  6  7  8  9  10
是否交卷   √  √  √  ×  √  √  √  √  √  √

读取到一个已交卷学号 id 时:submitted[id] = true

最后从 1 扫描到 N,所有 submitted[i] == false 的学号就是未交卷学生。

这样还有一个好处:因为本身就是按照 1 ~ N 扫描,所以结果天然按照学号升序排列,完全不需要再排序。

六、Python算法源码

import sys

# 一次读取全部输入,并按照行进行拆分
lines = sys.stdin.read().splitlines()

if not lines:
    sys.exit(0)

n = int(lines[0].strip())

# submitted[i] 表示学号 i 是否已经交卷
# 使用 n + 1 的长度,可以直接使用学号作为数组下标
submitted = [False] * (n + 1)

# 第二行可能为空,表示没有任何学生交卷
line = lines[1].strip() if len(lines) > 1 else ""

if line:
    for item in line.split(","):
        student_id = int(item.strip())
        submitted[student_id] = True

/*
Python 中这里不能使用上面的注释形式,实际代码继续如下
*/

七、JavaScript算法源码

const fs = require('fs');

const input = fs.readFileSync(0, 'utf8').split(/\r?\n/);

const n = Number((input[0] || '').trim());

/*
 * submitted[i] 表示学号 i 是否已经交卷。
 * 长度设置为 n + 1,可以直接使用学号作为数组下标。
 */
const submitted = new Array(n + 1).fill(false);

// 第二行允许为空,空行表示没有任何学生交卷
const line = (input[1] || '').trim();

if (line.length > 0) {
    const ids = line.split(',');

    for (const item of ids) {
        const studentId = Number(item.trim());
        submitted[studentId] = true;
    }
}

const result = [];

/*
 * 从 1 到 n 顺序检查。
 * 没有被标记的学生就是未交卷学生。
 * 因为遍历顺序就是学号升序,所以无需额外排序。
 */
for (let i = 1; i <= n; i++) {
    if (!submitted[i]) {
        result.push(i);
    }
}

console.log(result.join(','));

八、C算法源码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    int n;

    if (scanf("%d", &n) != 1) {
        return 0;
    }

    /*
     * scanf 读取 N 后,输入缓冲区中还留有换行符。
     * 这里将第一行剩余内容读取掉,
     * 后面才能正确使用 fgets 读取第二行。
     */
    int ch;
    while ((ch = getchar()) != '\n' && ch != EOF) {
    }

    /*
     * submitted[i] 表示学号 i 是否已经交卷。
     *
     * calloc 会自动把内存初始化为 0:
     * 0 -> 未交卷
     * 1 -> 已交卷
     */
    int *submitted =
        (int *)calloc((size_t)n + 1, sizeof(int));

    if (submitted == NULL) {
        return 0;
    }

    char line[1024] = {0};

    if (fgets(line, sizeof(line), stdin) != NULL) {

        /*
         * 使用 strtok 按逗号拆分学号。
         * 如果第二行为空,则不会得到有效学号。
         */
        char *token = strtok(line, ",\r\n");

        while (token != NULL) {
            int studentId = atoi(token);

            submitted[studentId] = 1;

            token = strtok(NULL, ",\r\n");
        }
    }

    int first = 1;

    /*
     * 从 1 到 n 顺序扫描。
     * 未被标记的学生就是未交卷学生。
     * 顺序遍历可以直接保证结果按照学号升序。
     */
    for (int i = 1; i <= n; i++) {
        if (!submitted[i]) {

            // 除第一个学号外,其余学号前面添加逗号
            if (!first) {
                printf(",");
            }

            printf("%d", i);
            first = 0;
        }
    }

    printf("\n");

    free(submitted);

    return 0;
}

九、C++算法源码

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

int main() {
    int n;

    cin >> n;

    // 丢弃读取 N 后剩余的换行符
    cin.ignore();

    /*
     * submitted[i] 表示学号 i 是否已经交卷。
     * vector<bool> 只需要保存 true / false 状态,
     * 非常适合本题。
     */
    vector<bool> submitted(n + 1, false);

    string line;
    getline(cin, line);

    if (!line.empty()) {
        stringstream ss(line);
        string token;

        /*
         * 按逗号拆分第二行。
         * 每读取到一个学号,就在 submitted 中进行标记。
         */
        while (getline(ss, token, ',')) {
            int studentId = stoi(token);

            submitted[studentId] = true;
        }
    }

    bool first = true;

    /*
     * 从 1 到 n 顺序检查。
     * false 表示这个学生没有出现在交卷名单中,
     * 因此属于未交卷学生。
     *
     * 由于本身就是按照升序遍历,所以无需排序。
     */
    for (int i = 1; i <= n; i++) {
        if (!submitted[i]) {

            if (!first) {
                cout << ',';
            }

            cout << i;
            first = false;
        }
    }

    cout << '\n';

    return 0;
}


🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 新系统 200分)

🏆本文收录于,华为OD机试真题(Python/JS/C/C++)

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值