JavaScript is required

2025-12-25-面试算法ACM模式构建构建输入输出模板(Javascript)

我觉得就应该像力扣那样搞关键函数模式,至少前端岗可以这么搞 上 ACM 感觉除了 cpp 和 py 其他处理输入输出要麻烦死,遂在这里记录 js 的处理模板

算法#算法#ACM#JavaScript#面试

我觉得就应该像力扣那样搞关键函数模式,至少前端岗可以这么搞 上 ACM 感觉除了 cpp 和 py 其他处理输入输出要麻烦死,遂在这里记录 js 的处理模板

一、基础模板

我们先来看一个基础模板

js
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // 直接输出需要的字符串,不需要处理输入
  console.log("Hello Nowcoder!");
})();

我们接下来逐行解析下每行代码的作用

1. 引入 readline 模块并创建接口
js
const rl = require("readline").createInterface({ input: process.stdin });
  • require("readline"):引入 Node.js 内置的readline模块,这个模块用于从命令行(标准输入)读取一行一行的输入。
  • createInterface({ input: process.stdin }):创建一个输入接口,指定输入源为process.stdin(标准输入,也就是用户在控制台输入的内容)。
  • 变量rl就是这个输入接口的实例,后续通过它来控制输入的读取。
2. 创建异步迭代器
js
var iter = rl[Symbol.asyncIterator]();
  • Symbol.asyncIterator是 Javascript 的一个内置符号,用于定义对象的异步迭代器
  • 这里通过rl[Symbol.asyncIterator]()获取 rl 接口的异步迭代器,赋值给iter。
  • 异步迭代器的作用是:可以通过next()方法异步地获取下一行输入(因为输入是用户手动输入的,属于异步操作)。
3. 定义读取一行输入的函数
js
const readline = async () => (await iter.next()).value;
  • 这是一个异步函数(async标记),作用是读取一行输入。
  • 调用iter.next()会返回一个 Promise,await会等待这个 Promise 完成,获取下一行输入的结果。
  • 结果的value属性就是读取到的一行字符串(如果没有更多输入,value会是undefined)。
  • 简单说:调用readline()就可以得到一行输入的内容(字符串类型)
4. 立即执行的异步函数(核心逻辑区)
js
void (async function () {
  // Write your code here 👉 你的核心代码写在这里
  // 直接输出需要的字符串,不需要处理输入 console.log("Hello Nowcoder!");
})();

这是整个代码的执行入口,也就是你需要编写核心逻辑的地方,我们拆解一下:

  • void async function (){...}():这是一个立即执行的异步函数表达式 (IIFE)。 tags:
    • async标记:允许函数内部使用 await 关键字(因为读取输入输出是异步操作)。
    • void:避免函数执行后返回值可能导致的语法问题,单纯让函数执行。
    • 最后的():表示定义后立即执行这个函数。

核心代码写在哪里?

答案是:写在void async function () { ... }这个函数内部(也就是注释// Write your code here的位置)。根据题目的输入格式不同,你需要修改这个区域的代码。具体常见的输入格式见我第二部分详细讲解。

总结

这个模板的作用是标准化输入读取流程:

  1. 准备好读取输入的工具(rl接口,iter迭代器,readline函数)。
  2. 在立即执行的异步函数中,通过await readline()获取输入。
  3. 在函数内部编写你的核心逻辑(处理输入、计算、输出结果)。

二、常见出题形式

1.单组 A+B

描述

给定两个整数a和b,请你求出a + b的值。

输入描述:

第一行有两个整数a和b

输出描述:

输入一个整数,代表a + b的值。

示例
js
输入:
1 2
输出:
3
js
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // Write your code here
  while ((line = await readline())) {
    let tokens = line.split(" ");
    let a = parseInt(tokens[0]);
    let b = parseInt(tokens[1]);
    console.log(a + b);
  }
})();
核心逻辑解析

函数内部的while循环:

js
while(line = await readline()) { ... }
  • 作用:持续读取每一行输入 ,直到没有更多输入(readline()返回undefined,循环终止)。
  • line = await readline():先调用readline()读取每一行输入,赋值给line。
  • 当没有输入时,readline()先返回undefined,循环条件为false,退出循环。

循环内部的代码

js
let tokens = line.split(" "); // 将一行输入按空格分割成数组(比如输入"1 2",得到["1", "2"])
let a = parseInt(tokens[0]); // 将第一个元素转为整数
let b = parseInt(tokens[1]); // 将第二个元素转为整数 console.log(a + b); // 输出结果

2.多组_A+B_EOF 形式

描述

给定若干组测试数据,读取至文件末尾为止,每组数据有两个整数 a 和 b,请你求出 a + b 的值。

输入描述

每行有两个整数 a 和 b,读取至文件末尾为止

输出描述

输出若干行,每行一个整数,代表 a + b 的值。

示例
js
输入:
1 2
114 514
2024 727
输出:
3
628
2751
js
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // 循环读取每一行输入,直到没有更多输入(EOF)
  while ((line = await readline())) {
    // 将一行输入按空格分割成数组(例如"1 2"分割为["1", "2"])
    let tokens = line.split(" ");
    // 将分割后的字符串转为整数
    let a = parseInt(tokens[0]);
    let b = parseInt(tokens[1]);
    // 输出两数之和
    console.log(a + b);
  }
})();

3.多组_A+B_T 组形式

描述

给定 t 组测试数据。每组数据有两个整数 a 和 b,请你求出 a + b 的值。

输入描述

第一行有一个整数 t,每行有两个整数 a 和 b

输出描述

输出 t 行,每行一个整数,代表 a + b 的值。

示例
js
输入:
3
1 2
114 514
2024 727
输出:
3
628
2751
js
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // 第一步:读取第一行,获取测试用例数量T
  let T = parseInt(await readline());

  // 第二步:循环T次,处理每组数据
  for (let i = 0; i < T; i++) {
    // 读取一行输入
    let line = await readline();
    // 分割成两个数字
    let tokens = line.split(" ");
    let a = parseInt(tokens[0]);
    let b = parseInt(tokens[1]);
    // 输出结果
    console.log(a + b);
  }
})();

4.多组A+B零尾模式

描述

给定若干组测试数据,最后一组数据为 0 0,作为输入的结尾。每组数据有两个整数 a 和 b,请你求出 a + b 的值。

输入描述

每行有两个整数 a 和 b,最后一组数据为 0 0,作为输入的结尾。

输出描述

输出若干行,每行一个整数,代表 a + b 的值。

示例
js
输入:
1 2
114 514
2024 727
0 0
输出:
3
628
2751
js
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // 循环读取每一行输入
  while ((line = await readline())) {
    // 分割并转换为数字
    let tokens = line.split(" ");
    let a = parseInt(tokens[0]);
    let b = parseInt(tokens[1]);

    // 关键:判断是否为0 0,是则终止循环
    if (a === 0 && b === 0) {
      break; // 退出循环,不再处理后续输入
    }

    // 不是终止条件则输出结果
    console.log(a + b);
  }
})();

5.单组_一维数组

示例
js
输入:
3
1 4 7
输出:
12
js
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // 第一步:读取第一行,获取数字的个数n
  let n = parseInt(await readline());

  // 第二步:读取第二行,获取包含n个数字的字符串
  let line = await readline();

  // 第三步:对字符串进行处理,转化为数字数组
  let nums = line
    .split(" ")
    .filter((x) => x)
    .map(Number); // 用空格分割,过滤空值

  // 第四步:计算数组中所有数字的总和
  let sum = nums.reduce((acc, curr) => acc + curr, 0);

  // 第五步:输出总和
  console.log(sum);
})();

6.多组_一维数组_T 组形式

示例
js
输入:
3
3
1 4 7
1
1000
2
1 2
输出:
12
1000
3
js
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // 读取测试用例总数T
  const T = parseInt(await readline());

  // 循环处理每组数据
  for (let i = 0; i < T; i++) {
    // 读取当前组的元素个数n
    const n = parseInt(await readline());

    // 读取当前组的数组元素行
    const arrayLine = await readline();

    // 将字符串分割为数字数组
    const numbers = arrayLine
      .split(" ")
      .filter((x) => x)
      .map(Number);

    // 计算数组总和(使用reduce累加,初始值为0)
    const sum = numbers.reduce((acc, current) => acc + current, 0);

    // 输出当前组的总和
    console.log(sum);
  }
})();

7.单组_二维数组

示例
js
输入:
3 4
1 2 3 4
5 6 7 8
9 10 11 12
输出:
78
js
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // 1. 读取第一行,获取二维数组的行数m和列数n
  let firstLine = await readline();
  let [m, n] = firstLine.split(" ").map(Number); // m=3, n=4(对应示例输入)

  let totalSum = 0; // 存储总和

  // 2. 循环读取m行数据(二维数组的每一行)
  for (let i = 0; i < m; i++) {
    let row = await readline(); // 读取一行数据(如"1 2 3 4")
    let nums = row
      .split(" ")
      .filter((x) => x)
      .map(Number); // 转为数字数组(如[1,2,3,4])

    // 3. 累加当前行的所有元素到总和
    let rowSum = nums.reduce((acc, curr) => acc + curr, 0);
    totalSum += rowSum;
  }

  // 4. 输出二维数组所有元素的总和
  console.log(totalSum);
})();

8.多组_二维数组_T 组形式

示例
js
输入:
3
3 4
1 2 3 4
5 6 7 8
9 10 11 12
1 1
2024
3 2
1 1
4 5
1 4
输出:
78
2024
16

9.单组_字符串

描述

给定一个长度为n的字符串s,请你将其倒置,然后输出。

输入描述

第一行有一个整数n,第二行有一个字符串s,仅包含小写英文字符。

输出描述

输出一个字符串,代表倒置后的字符串s。

示例
js
输入:
5
abcde
输出:
edcba
js
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // 1. 读取第一行:字符串的长度n(本题中可忽略具体值,仅用于匹配输入格式)
  const n = parseInt(await readline());

  // 2. 读取第二行:需要反转的字符串
  const str = await readline();

  // 3. 反转字符串:
  //    - split('') 将字符串转为字符数组(如"abcde" → ['a','b','c','d','e'])
  //    - reverse() 反转数组(→ ['e','d','c','b','a'])
  //    - join('') 将数组转回字符串(→ "edcba")
  const reversedStr = str.split("").reverse().join("");

  // 4. 输出反转后的字符串
  console.log(reversedStr);
})();

10.多组_字符串_T 组形式

描述

给定t组询问,每次只给出一个长度为n的字符串s,请你将其倒置,然后输出。

输入描述

第一行有一个整数t,随后t组数据。每组的第一行有一个整数n,每组的第二行有一个字符串s,仅包含小写英文字符。

输出描述

输出t行,每行一个字符串,代表倒置后的字符串s。

示例
js
输入:
3
5
abcde
8
redocwon
9
tfarcenim
输出:
edcba
nowcoder
minecraft
js
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // 1. 读取测试用例总数T
  const T = parseInt(await readline());

  // 2. 循环处理每组字符串
  for (let t = 0; t < T; t++) {
    // 2.1 读取当前组的字符串长度n(仅用于匹配输入格式,反转逻辑不依赖此值)
    const n = parseInt(await readline());

    // 2.2 读取当前组需要反转的字符串
    const str = await readline();

    // 2.3 反转字符串:拆分为字符数组 → 反转数组 → 拼接为字符串
    const reversedStr = str.split("").reverse().join("");

    // 2.4 输出反转后的字符串
    console.log(reversedStr);
  }
})();

11.单组_二维字符数组

输入描述

第一行有两个整数n和m,随后n行,每行有m个字符,仅包含小写英文字符。

输出描述

输出一个二维字符数组。

示例
js
输入:
3 4
abcd
efgh
ijkl
输出:
lkji
hgfe
dcba
js
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // 1. 读取第一行,获取二维数组的行数m和列数n
  const [m, n] = (await readline())
    .split(" ")
    .filter((x) => x)
    .map(Number);

  // 2. 读取m行字符串,存储到数组中
  const rows = [];
  for (let i = 0; i < m; i++) {
    rows.push(await readline());
  }

  // 3. 处理逻辑:
  //    a. 先将每行字符串反转(如"abcd" → "dcba")
  //    b. 再将所有行的顺序反转(如[行1, 行2, 行3] → [行3, 行2, 行1])
  const reversedRows = rows
    .map((row) => row.split("").reverse().join("")) // 每行字符反转
    .reverse(); // 行顺序反转

  // 4. 逐行输出处理后的结果
  reversedRows.forEach((row) => console.log(row));
})();

12.多组_带空格的字符串_T 组形式

描述

给定t组询问,每次给出一个长度为n的带空格的字符串s,请你去掉空格之后,将其倒置,然后输出。

输入描述

第一行有一个整数t,随后有t组数据。每组的第一行有一个整数n,每组的第二行有一个字符串s,仅包含小写英文字符和空格,保证字符串首尾都不是空格。

输出描述

输出 t 行,每行一个字符串,代表倒置后的字符串s。

示例
js
输入:
3
9
one space
11
two  spaces
14
three   spaces
输出:
ecapseno
secapsowt
secapseerht
js
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // 1. 读取测试用例总数T
  const T = parseInt(await readline());

  // 2. 循环处理每组字符串
  for (let t = 0; t < T; t++) {
    // 2.1 读取当前组的字符串总长度n(用于匹配输入格式)
    const n = parseInt(await readline());

    // 2.2 读取带空格的字符串
    const str = await readline();

    // 2.3 处理逻辑:
    //    a. 先将字符串所有字符(包括空格)反转
    //    b. 再去除反转后字符串中的所有空格
    const processed = str
      .split("") // 拆分为字符数组(含空格)
      .reverse() // 反转所有字符(包括空格)
      .join("") // 拼接回字符串
      .replace(/\s+/g, ""); // 去除所有空格(\s+匹配任意空白字符)

    // 2.4 输出处理结果
    console.log(processed);
  }
})();

13.单组_保留小数位数

描述

给定一个小数 n ,请你保留 3 位小数后输出。

如果原来的小数位数少于 3 ,需要补充 0 。

如果原来的小数位数多于 3 ,需要四舍五入到 3 位。

输出描述

输出一个小数,保留 3 位。

示例
js
输入:
1.23
输出:
1.230

输入:
114.514
输出:
114.514

输入:
123
输出:
123.000
js
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // 1. 读取输入的小数(单组输入,只需读一次)
  const numStr = await readline();

  // 2. 将字符串转换为浮点数
  const num = parseFloat(numStr);

  // 3. 保留3位小数:toFixed(3)会自动补零,确保结果是3位小数
  const result = num.toFixed(3);

  // 4. 输出格式化后的结果
  console.log(result);
})();

14.单组_补充前导零

描述

给定一个正整数 n ,请你保留 9 个数位,然后输出。

如果数位少于 9 个,那么需要补充前导零。

输出描述

输出一个小数,保留 3 位。

示例
js
输入:
123
输出:
000000123

输入:
123456789
输出:
123456789
js
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // 1. 读取输入的数字(单组输入,读取一行即可)
  const numStr = await readline();

  // 2. 补充前导零至9位:
  //    - padStart(9, '0') 表示如果字符串长度不足9位,在前面补'0'直到长度为9
  const result = numStr.padStart(9, "0");

  // 3. 输出处理后的结果
  console.log(result);
})();

常用方法

  • parseInt():将字符串转化为整数。
  • parseFloat():将字符串转化为浮点数。
  • split():将字符串按指定分隔符分割成数组。
  • reverse():反转数组。
  • join():将数组元素按指定分隔符拼接成字符串。
  • padStart():在字符串前面补充指定字符,直到字符串长度达到指定长度。
  • line = await readline():要注意 await readline()获取的是一段字符串,后面我们还要自己将它分割或者转化为其他数据类型。
  • let tokens = line.split(' '):这段代码作用是,将一行输入按空格分割成数组(例如"1 2"分割为"1", "2")。
  • let a = parseInt(tokens[0]):这段代码的作用是,将分割的字符转化为数字。

再配合while和for语句差不多可以应对各种题型了