2025-12-25-面试算法ACM模式构建构建输入输出模板(Javascript)
我觉得就应该像力扣那样搞关键函数模式,至少前端岗可以这么搞 上 ACM 感觉除了 cpp 和 py 其他处理输入输出要麻烦死,遂在这里记录 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 模块并创建接口
const rl = require("readline").createInterface({ input: process.stdin });require("readline"):引入 Node.js 内置的readline模块,这个模块用于从命令行(标准输入)读取一行一行的输入。createInterface({ input: process.stdin }):创建一个输入接口,指定输入源为process.stdin(标准输入,也就是用户在控制台输入的内容)。- 变量
rl就是这个输入接口的实例,后续通过它来控制输入的读取。
2. 创建异步迭代器
var iter = rl[Symbol.asyncIterator]();Symbol.asyncIterator是 Javascript 的一个内置符号,用于定义对象的异步迭代器- 这里通过
rl[Symbol.asyncIterator]()获取 rl 接口的异步迭代器,赋值给iter。 - 异步迭代器的作用是:可以通过
next()方法异步地获取下一行输入(因为输入是用户手动输入的,属于异步操作)。
3. 定义读取一行输入的函数
const readline = async () => (await iter.next()).value;- 这是一个异步函数(
async标记),作用是读取一行输入。 - 调用
iter.next()会返回一个 Promise,await会等待这个 Promise 完成,获取下一行输入的结果。 - 结果的
value属性就是读取到的一行字符串(如果没有更多输入,value会是undefined)。 - 简单说:调用
readline()就可以得到一行输入的内容(字符串类型)
4. 立即执行的异步函数(核心逻辑区)
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的位置)。根据题目的输入格式不同,你需要修改这个区域的代码。具体常见的输入格式见我第二部分详细讲解。
总结
这个模板的作用是标准化输入读取流程:
- 准备好读取输入的工具(
rl接口,iter迭代器,readline函数)。 - 在立即执行的异步函数中,通过
await readline()获取输入。 - 在函数内部编写你的核心逻辑(处理输入、计算、输出结果)。
二、常见出题形式
1.单组 A+B
描述
给定两个整数a和b,请你求出a + b的值。
输入描述:
第一行有两个整数a和b
输出描述:
输入一个整数,代表a + b的值。
示例
输入:1 2输出:3const 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循环:
while(line = await readline()) { ... }- 作用:持续读取每一行输入 ,直到没有更多输入(
readline()返回undefined,循环终止)。 line = await readline():先调用readline()读取每一行输入,赋值给line。- 当没有输入时,
readline()先返回undefined,循环条件为false,退出循环。
循环内部的代码
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 的值。
示例
输入:1 2114 5142024 727输出:36282751const 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 的值。
示例
输入:31 2114 5142024 727输出:36282751const 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 的值。
示例
输入:1 2114 5142024 7270 0输出:36282751const 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.单组_一维数组
示例
输入:31 4 7输出:12const 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 组形式
示例
输入:331 4 71100021 2输出:1210003const 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.单组_二维数组
示例
输入:3 41 2 3 45 6 7 89 10 11 12输出:78const 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 组形式
示例
输入:33 41 2 3 45 6 7 89 10 11 121 120243 21 14 51 4输出:78202416const 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 读取当前组的行数m和列数n const [m, n] = (await readline()) .split(" ") .filter((x) => x) .map(Number);
let totalSum = 0; // 存储当前组的总和
// 2.2 读取m行数据(二维数组的每一行) for (let i = 0; i < m; i++) { const row = (await readline()) .split(" ") .filter((x) => x) .map(Number); // 累加当前行的所有元素 const rowSum = row.reduce((acc, curr) => acc + curr, 0); totalSum += rowSum; }
// 2.3 输出当前组的总和 console.log(totalSum); }})();9.单组_字符串
描述
给定一个长度为n的字符串s,请你将其倒置,然后输出。
输入描述
第一行有一个整数n,第二行有一个字符串s,仅包含小写英文字符。
输出描述
输出一个字符串,代表倒置后的字符串s。
示例
输入:5abcde输出:edcbaconst 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。
示例
输入:35abcde8redocwon9tfarcenim输出:edcbanowcoderminecraftconst 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个字符,仅包含小写英文字符。
输出描述
输出一个二维字符数组。
示例
输入:3 4abcdefghijkl输出:lkjihgfedcbaconst 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。
示例
输入:39one space11two spaces14three spaces输出:ecapsenosecapsowtsecapseerhtconst 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 位。
示例
输入:1.23输出:1.230
输入:114.514输出:114.514
输入:123输出:123.000const 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 位。
示例
输入:123输出:000000123
输入:123456789输出:123456789const 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语句差不多可以应对各种题型了
分享到社交平台
将本文分享给你的朋友们
Zhongye