Bootstrap

华为OD机试 - 火车进站(Python/JS/C/C++ 牛客练习题 HJ108)

在这里插入图片描述

2025华为OD机试题库(按算法分类):2025华为OD统一考试题库清单(持续收录中)以及考点说明(Python/JS/C/C++)

专栏导读

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

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

一、题目描述

给定一个正整数N代表火车数量,0<N<10,接下来输入火车入站的序列,一共N辆火车,每辆火车以数字1-9编号,火车站只有一个方向进出,同时停靠在火车站的列车中,只有后进站的出站了,先进站的才能出站。

要求输出所有火车出站的方案,以字典序排序输出。

二、输入描述

第一行输入一个正整数N(0 < N <= 10),第二行包括N个正整数,范围为1到10。

三、输出描述

输出以字典序从小到大排序的火车出站序列号,每个编号以空格隔开,每个输出序列换行。

四、测试用例

1、输入

3
1 2 3

2、输出

1 2 3
1 3 2
2 1 3
2 3 1
3 2 1

五、解题思路

  1. 首先通过输入获取火车的数量N和火车入站序列id;
  2. 创建一个结果集列表,用于存储所有火车出站的方案;
  3. 创建一个栈,用于模拟火车的进站和出站过程;
  4. 调用递归函数trainOut,开始计算火车出站的方案;
  5. 递归函数trainOut的参数包括当前考虑的火车编号i,当前栈的状态s,当前已出站的火车序列str,已出站的火车数量n;
  6. 如果所有火车均已出站(n等于火车数量N),将当前结果保存到结果集列表中;
  7. 如果栈非空,表示可以将栈顶火车出栈,将栈顶元素弹出,递归调用trainOut函数,更新已出站的火车序列和数量;
  8. 将弹出的火车编号加入结果序列str,并加上空格;
  9. 恢复栈的状态,将弹出的火车编号重新入栈;
  10. 如果还有未考虑的火车(i小于火车数量N),将下一辆火车入栈,递归调用trainOut函数,更新已出站的火车序列和数量;
  11. 恢复栈的状态,将最近入栈的火车出栈;
  12. 最后,对结果集列表进行字典序排序,并依次输出每个出站序列;

六、Python算法源码

# 定义递归函数,生成所有出站序列
def trainOut(id, i, s, sequence, n, results):
    # 如果所有火车都已出站,则将当前序列加入结果列表
    if n == len(id):
        results.append(sequence)
        return
    # 如果栈不为空,则尝试出站操作
    if s:
        temp = s.pop()  # 弹出栈顶火车
        # 递归调用,将该火车加入序列,出站数量加1
        trainOut(id, i, s, sequence + str(temp) + " ", n + 1, results)
        s.append(temp)  # 恢复现场,将火车重新压回栈中
    # 如果还有火车未入站,则进行入站操作
    if i < len(id):
        s.append(id[i])  # 将下一个火车入站(压入栈中)
        trainOut(id, i + 1, s, sequence, n, results)  # 递归调用,入站索引加1
        s.pop()  # 恢复现场,移除刚刚入站的火车

# 主函数入口
def main():
    import sys  # 导入系统模块,用于读取输入
    # 读取标准输入所有数据,并按空白字符分割
    data = sys.stdin.read().split()
    if not data:
        return
    n = int(data[0])  # 第一项为火车数量
    # 后续n项为火车入站序列,转换为整数列表
    id = [int(x) for x in data[1:1+n]]
    results = []  # 用于保存所有生成的出站序列
    s = []  # 用列表模拟栈结构
    # 开始递归搜索,初始入站索引为0,已出站火车数为0,初始序列为空
    trainOut(id, 0, s, "", 0, results)
    results.sort()  # 按字典序排序结果
    # 输出每个出站序列
    for res in results:
        print(res)

# 如果作为主程序运行,则调用main函数
if __name__ == '__main__':
    main()

七、JavaScript算法源码

// 定义递归函数,生成所有出站序列
function trainOut(id, i, s, sequence, n, results) {
    // 如果所有火车都已出站,则将当前序列加入结果数组
    if (n === id.length) {
        results.push(sequence);
        return;
    }
    // 如果栈不为空,则尝试出站操作
    if (s.length > 0) {
        let temp = s.pop(); // 弹出栈顶火车
        // 递归调用,将该火车加入序列,出站数量加1
        trainOut(id, i, s, sequence + temp + " ", n + 1, results);
        s.push(temp); // 恢复现场,将火车重新压回栈中
    }
    // 如果还有火车未入站,则进行入站操作
    if (i < id.length) {
        s.push(id[i]); // 将下一个火车入站(压入栈中)
        trainOut(id, i + 1, s, sequence, n, results); // 递归调用,入站索引加1
        s.pop(); // 恢复现场,移除刚刚入站的火车
    }
}

// 主函数入口
function main() {
    // 读取标准输入(使用fs模块同步读取)
    let input = require('fs').readFileSync(0, 'utf-8').trim().split(/\s+/);
    if (input.length === 0) return;
    let n = parseInt(input[0]); // 第一项为火车数量
    let id = []; // 用于保存火车入站序列
    // 将后续n项转换为整数并存入数组
    for (let i = 0; i < n; i++) {
        id.push(parseInt(input[i + 1]));
    }
    let results = []; // 保存所有出站序列
    let s = []; // 用数组模拟栈
    // 开始递归搜索,初始入站索引为0,出站数为0,序列为空
    trainOut(id, 0, s, "", 0, results);
    results.sort(); // 按字典序排序
    // 输出每个出站序列,每行一个
    results.forEach(line => {
        console.log(line);
    });
}
// 调用主函数
main();

八、C算法源码

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

#define MAX_SOL 10000    // 假设最多10000个序列
#define MAX_LEN 50       // 每个序列的最大字符长度

// 全局数组用于存储所有出站序列
char* solutions[MAX_SOL];
int solCount = 0; // 当前存储的序列数量

// 交换两个字符串指针(用于qsort排序)
int cmp(const void *a, const void *b) {
    return strcmp(*(char **)a, *(char **)b);
}

/*
 * 递归函数,生成所有出站序列
 * id: 输入火车序列数组
 * n: 火车数量
 * i: 当前入站火车索引
 * s: 用数组模拟的栈,保存当前站内火车
 * top: 栈顶指针(当前栈中元素个数)
 * seq: 当前形成的出站序列字符串
 * seqLen: 当前字符串长度
 */
void trainOut(int id[], int n, int i, int s[], int top, char seq[], int seqLen) {
    // 如果所有火车都已出站,则将当前序列保存
    if (seqLen >= 0 && seqLen > 0 && solCount < MAX_SOL && (seqLen - 1) >= 0) {
        // 当出站火车数量等于n时,seq中已经有n个数字(以及空格)
        if ((seqLen - 1) / 2 == n) {
            seq[seqLen] = '\0'; // 结束字符串
            solutions[solCount] = (char*)malloc((seqLen + 1) * sizeof(char));
            strcpy(solutions[solCount], seq);
            solCount++;
            return;
        }
    }
    // 如果栈非空,则尝试出站操作
    if (top > 0) {
        int temp = s[top - 1]; // 获取栈顶元素
        top--;               // 出栈
        // 记录出站操作,将数字及空格加入seq中
        int len = sprintf(seq + seqLen, "%d ", temp);
        trainOut(id, n, i, s, top, seq, seqLen + len);
        // 回溯恢复现场:撤销添加的数字
        seqLen -= len;
        seq[seqLen] = '\0';
        s[top] = temp; // 将火车压回栈中
        top++;
    }
    // 如果还有火车未入站,则进行入站操作
    if (i < n) {
        s[top] = id[i];  // 将火车入栈
        trainOut(id, n, i + 1, s, top + 1, seq, seqLen);
        // 回溯:不需要显式出栈,因下次覆盖即可
    }
}

int main() {
    int n;
    // 读取火车数量
    if (scanf("%d", &n) != 1) return 1;
    int *id = (int*)malloc(n * sizeof(int));
    for (int i = 0; i < n; i++) {
        scanf("%d", &id[i]); // 读取每辆火车编号
    }
    int s[20];         // 栈数组(n<=10,预留足够空间)
    char seq[MAX_LEN] = ""; // 存储当前出站序列字符串
    solCount = 0;      // 初始化结果计数
    // 开始递归搜索,初始入站索引为0,栈空,序列长度0
    trainOut(id, n, 0, s, 0, seq, 0);
    // 对结果进行字典序排序
    qsort(solutions, solCount, sizeof(char*), cmp);
    // 输出所有序列
    for (int i = 0; i < solCount; i++) {
        printf("%s\n", solutions[i]);
        free(solutions[i]); // 释放内存
    }
    free(id); // 释放输入数组内存
    return 0;
}

九、C++算法源码

#include <iostream>
#include <vector>
#include <stack>
#include <string>
#include <algorithm>
using namespace std;

// 全局变量,用于存储所有出站序列
vector<string> results;

/*
 * 递归函数,生成所有出站序列
 * id: 输入火车序列(vector<int>)
 * i: 当前入站火车的索引
 * s: 用stack<int>模拟火车站
 * seq: 当前已形成的出站序列字符串
 * n: 当前已出站火车的数量
 */
void trainOut(const vector<int>& id, int i, stack<int>& s, string seq, int n) {
    if(n == id.size()) { // 当所有火车均出站
        results.push_back(seq); // 保存当前序列
        return;
    }
    // 如果栈不为空,则进行出站操作
    if(!s.empty()) {
        int temp = s.top(); // 获取栈顶火车
        s.pop();           // 执行出站操作
        trainOut(id, i, s, seq + to_string(temp) + " ", n + 1); // 递归调用
        s.push(temp);      // 回溯恢复现场
    }
    // 如果还有火车未入站,则进行入站操作
    if(i < id.size()) {
        s.push(id[i]); // 将下一辆火车入站
        trainOut(id, i + 1, s, seq, n); // 递归调用,入站索引增加
        s.pop(); // 回溯恢复现场
    }
}

int main() {
    int n;
    cin >> n; // 读取火车数量
    vector<int> id(n);
    for (int i = 0; i < n; i++) {
        cin >> id[i]; // 读取每辆火车的编号
    }
    stack<int> s; // 用于模拟火车站的栈
    trainOut(id, 0, s, "", 0); // 开始递归搜索
    sort(results.begin(), results.end()); // 按字典序排序结果
    // 输出所有出站序列
    for (const auto& str : results) {
        cout << str << endl;
    }
    return 0;
}


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

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

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

在这里插入图片描述

;