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

如何高效查找50万单词的变位词并优化JSON存储?

变位词生成代码的速度与体积优化方案

一、速度优化:从根源避免组合爆炸

1. 预构建词表的变位词索引

先对50万词表做一次预处理,把所有3字母及以上的单词按字母排序后的字符串分组(比如"eye""yee""eey"都归到key"eey"下),同时预计算每组的字母频率,避免后续重复计算。这一步仅需执行一次,后续查询直接复用索引。

代码示例(Node.js环境):

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

// 生成单词的字母频率数组(a-z对应索引0-25)
const getLetterFreq = (word) => {
  const freq = new Array(26).fill(0);
  for (const c of word.toLowerCase()) {
    const idx = c.charCodeAt(0) - 97;
    if (idx >= 0 && idx < 26) freq[idx]++;
  }
  return freq;
};

// 流式读取词表,构建变位词索引
const buildAnagramIndex = async (wordListPath) => {
  const index = new Map();
  const rl = readline.createInterface({
    input: fs.createReadStream(wordListPath),
    crlfDelay: Infinity
  });

  for await (const word of rl) {
    const trimmedWord = word.trim();
    if (trimmedWord.length < 3) continue; // 跳过短词
    const sortedKey = trimmedWord.toLowerCase().split('').sort().join('');
    if (!index.has(sortedKey)) {
      index.set(sortedKey, {
        words: [],
        freq: getLetterFreq(sortedKey)
      });
    }
    index.get(sortedKey).words.push(trimmedWord);
  }
  // 保存索引到文件,后续直接加载复用
  fs.writeFileSync('anagram-index.json', JSON.stringify(Array.from(index.entries())));
  return index;
};

2. 基于字母频率匹配,替代子单词生成

不再生成输入单词的所有子组合,而是先计算输入单词的字母频率,然后遍历预构建的索引,检查索引中每组的频率是否是输入频率的子集(即每组的每个字母数量都不超过输入单词的对应字母数量),符合条件的组就是所有有效的子变位词。

代码示例:

// 加载预构建的索引
const loadAnagramIndex = () => {
  const data = fs.readFileSync('anagram-index.json', 'utf8');
  return new Map(JSON.parse(data));
};

// 查找输入单词的所有有效子变位词
const findSubAnagrams = (inputWord, index) => {
  const inputFreq = getLetterFreq(inputWord.toLowerCase());
  const result = new Set(); // 自动去重

  for (const [_, { words, freq }] of index) {
    let isValid = true;
    for (let i = 0; i < 26; i++) {
      if (freq[i] > inputFreq[i]) {
        isValid = false;
        break;
      }
    }
    if (isValid) {
      words.forEach(word => result.add(word));
    }
  }

  return Array.from(result);
};

3. 额外速度优化点

  • 用Map替代普通对象存储索引:Map的遍历和查找性能在大数据量下远优于Object。
  • 流式处理词表:避免一次性将50万词加载到内存,降低内存占用同时提升处理速度。
  • 预处理去重:如果词表存在重复单词,在构建索引时直接跳过重复项。

二、体积优化:压缩冗余数据

1. 按变位词组存储,避免重复key

原方案可能会为每个变位词单独创建key(比如{"eye": [...], "yee": [...]}),现在改为以排序后的字符串为唯一key,每个key对应一组变位词,比如{"eey": ["eye", "yee", "eey"]},直接减少大量重复的key条目。

2. 采用紧凑的存储结构

将索引存储为数组格式([[sortedKey, [word1, word2]], ...]),比JSON对象格式节省约10%-20%的字符体积。

3. 过滤冗余数据

  • 移除单元素变位词组:如果某个排序key下只有一个单词,且不是输入单词的必要结果,可以直接过滤(根据业务需求调整)。
  • 只保留小写单词:预处理时将所有单词转为小写,避免大小写重复(比如"Eye"和"eye"视为同一单词)。

4. 可选:压缩JSON文件

如果最终体积仍超标,可以用zlib对JSON文件进行压缩,Node.js示例:

const zlib = require('zlib');

// 压缩索引文件
const compressIndex = () => {
  const input = fs.createReadStream('anagram-index.json');
  const output = fs.createWriteStream('anagram-index.json.gz');
  input.pipe(zlib.createGzip()).pipe(output);
};

// 读取压缩后的索引
const loadCompressedIndex = async () => {
  const buffer = await fs.promises.readFile('anagram-index.json.gz');
  const decompressed = await zlib.gunzipSync(buffer);
  return new Map(JSON.parse(decompressed.toString()));
};

效果预估

  • 速度:预处理50万词表约5-10分钟,处理单条输入单词仅需毫秒级,1万词处理时间可控制在10分钟以内,50万词处理时间能压缩到20分钟左右。
  • 体积:按分组存储并过滤冗余后,JSON索引体积可控制在30-45MB,满足50MB以内的要求。

内容的提问来源于stack exchange,提问作者Lance Pollard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 07:54:56