You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

统计含指定重复字符的字符串行数及Node.js代码优化问询

优化海量字符串统计代码的方案

需求说明

现有一个每行由随机字母组成的文件,需要完成以下操作:

  1. 统计恰好包含任意字母出现2次的行数
  2. 统计恰好包含任意字母出现3次的行数
  3. 计算这两个行数的乘积
    文件可能包含海量字符串,需要优化现有代码提升性能。

现有代码的性能问题

原代码存在几个明显的性能瓶颈:

  • 保留了console.log(chars)调试输出,海量数据下会产生巨大IO开销,严重拖慢处理速度
  • 统计完字符计数后,两次通过Object.entries().filter().map()判断条件,做了大量不必要的数组转换和全量遍历操作
  • 使用对象存储字符计数,比数组索引访问的哈希开销更高
  • 用readFileSync一次性读取整个文件,海量场景下会直接占满内存导致崩溃

具体优化措施

  • 移除调试日志:直接删掉console.log(chars),生产环境绝对不能保留这类调试输出
  • 提前标记状态,避免二次遍历:在统计字符出现次数的过程中,直接标记是否出现过2次或3次的字符,不用等全部统计完再遍历计数结果
  • 用数组替代对象计数:因为字母是固定的26个小写字母(假设输入均为小写),用数组索引对应字母ASCII码,存取速度远快于对象
  • 改用流式读取文件:对于海量文件,用readline模块逐行读取处理,避免一次性加载整个文件到内存
  • 用some()替代filter+map:如果需要遍历计数结果,用some()方法,找到第一个符合条件的项就停止遍历,比生成完整数组高效得多

优化后的代码

情况1:文件体积适中(可一次性加载)

function solution(arrOfStrings) {
  let sumOfTwo = 0;
  let sumOfThree = 0;

  for (const str of arrOfStrings) {
    // 数组索引0对应a,1对应b...25对应z,初始化为0
    const countArr = new Array(26).fill(0);
    let hasTwo = false;
    let hasThree = false;

    for (const char of str) {
      const idx = char.charCodeAt(0) - 97; // 'a'的ASCII码为97
      countArr[idx]++;
      // 只要出现过一次2次/3次就标记为true
      if (countArr[idx] === 2) {
        hasTwo = true;
      } else if (countArr[idx] === 3) {
        hasThree = true;
        // 两个状态都满足时直接跳出循环,节省后续遍历时间
        if (hasTwo) break;
      }
    }

    if (hasTwo) sumOfTwo++;
    if (hasThree) sumOfThree++;
  }

  return sumOfTwo * sumOfThree;
}

const fs = require("fs");
const text = fs.readFileSync("./someTextFile.txt", "utf-8");
const arr = text.split("\n").filter(line => line.trim()); // 过滤空行
console.log(solution(arr));

情况2:海量文件(流式处理)

const fs = require("fs");
const readline = require("readline");

let sumOfTwo = 0;
let sumOfThree = 0;

function processLine(line) {
  if (!line.trim()) return;
  const countArr = new Array(26).fill(0);
  let hasTwo = false;
  let hasThree = false;

  for (const char of line) {
    const idx = char.charCodeAt(0) - 97;
    countArr[idx]++;
    if (countArr[idx] === 2) {
      hasTwo = true;
    } else if (countArr[idx] === 3) {
      hasThree = true;
      if (hasTwo) break;
    }
  }

  if (hasTwo) sumOfTwo++;
  if (hasThree) sumOfThree++;
}

async function processFile() {
  const rl = readline.createInterface({
    input: fs.createReadStream("./someTextFile.txt"),
    crlfDelay: Infinity // 兼容不同换行符
  });

  for await (const line of rl) {
    processLine(line);
  }

  console.log(sumOfTwo * sumOfThree);
}

processFile().catch(err => console.error(err));

额外说明

  • 如果输入字符串包含大写字母或其他字符,只需调整数组计数逻辑(比如扩展数组长度,或者增加字符范围判断)
  • 提前跳出字符遍历的逻辑:当hasTwo和hasThree都为true时,后续字符的计数变化不会影响结果(我们只关心是否出现过2次或3次,不关心出现次数更多的情况),所以可以直接终止当前字符串的遍历,节省时间

内容的提问来源于stack exchange,提问作者Akira Frank

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 14:45:33