【问题标题】:How can I efficiently search a string for occurrences of words?如何有效地搜索字符串中出现的单词?
【发布时间】:2022-01-24 23:12:02
【问题描述】:

基本上,我有一组单词,其中大约 250,000 个单词,并且希望能够返回在给定字符串中找到哪些单词的列表。

例如。输入字符串是'APPLEASEDITION',我想返回

[APP,APPLE,PLEA, PLEAS,PLEASE,PLEASED,lEA,LEAS,LEASE,LEASED,EA,EAS,EASE,EASED,AS,SEDITION,EDITION,IT,TI,ON]

我想出了这段代码,对于较短的输入字符串(最多 15 个字符),它比上面提到的方法运行得更快,但每个添加的字母都会使执行时间加倍:

const findWords = (instring, solutions = null) => {
  if (!solutions) solutions = new Set();
  if (!instring) {
    return new Set();
  }
  if (words[instring]) {
    solutions.add(instring);
  }
  const suffix = instring.slice(1);
  const prefix = instring.slice(0, instring.length - 1);

  if (!solutions.has(prefix))
    solutions = new Set([...solutions, ...findWords(prefix, solutions)]);
  if (!solutions.has(suffix))
    solutions = new Set([...solutions, ...findWords(suffix, solutions)]);
  return solutions;
};

想知道是否有人可以帮助我优化代码?

编辑:

我做了一个不同的解决方案,效果更好

const getAllSubstrings = (str) => {
  let result = [];

  for (let i = 0; i < str.length; i++) {
      for (let j = i + 1; j < str.length + 1; j++) {
          result.push(str.slice(i, j));
      }
  }
  return result;
}

const findWords = (instring) => {
  const solutions = []
  let subs = getAllSubstrings(instring)
  for (let sub of subs) {
    if (words[sub])
      solutions.push(sub)
  }
  return solutions
}

仍然对可能的改进持开放态度,但这对我的用例来说已经足够好了

【问题讨论】:

  • 您可能需要依赖某种启发式方法或索引来生成列表:您所做的只是通过所有组合暴力破解您的方式,这是低效且 O(n) 复杂的.
  • 你考虑过在服务器端做这个吗?或者使用现有的库(可能是用 WASM 编写的库)? JS 是单线程的,因此您需要在主线程之外高效地执行此操作(如 WASM)
  • 您是否考虑过使用trie?这似乎是解决问题的正确方法,特别是如果您想将字典重用于多个测试用例。

标签: javascript string algorithm search scrabble


【解决方案1】:
  1. 就目前而言,您的逻辑假设您的输入以短语开头或结尾,但不考虑中间的单词 - 您需要生成排列

  2. 将您的字典转换为以单词为键的哈希值 - O(n) => O(1) - 您可以通过检查 dictionary[possibleWord] 来检查字典中是否有可能的单词

  3. 您可以将字典单词数组转换为二叉搜索树或 trie - 将源文本转换为 BST/Tries 集合可能会带来性能优势,其中每个都代表一个可能的单词/排列,并且然后比较 BST/Tries 而不是字符串,但目前我不确定这会比字符串比较快。

您可以将长度限制为字典中单词给定排列的最大长度。你最终会得到很多排列,但可能比现在少。

正如 cmets 所说,您可能希望使用比 JS 更高效的语言或使用 WASM 来执行此服务器端以获得更多功能。

一些具有二叉搜索树工具的 javascript 库:

  1. 或者,您可以创建两个散列(一个排列,一个字典单词)或另一个用于创建“差异”或“重叠”的数据结构,并提取两个集合中的键.

【讨论】:

  • 也许我不明白,但它需要 O(1) 来检查一个单词是否在我的字典中,我的字典是一个集合,这不是减速。需要很长时间的是检查输入字符串的每个子字符串
  • 我的代码词即使输入不是以有效词开头或结尾,也不确定我是否遵循您的第一点
  • 至第 2 点 - 已经完成,请参见代码的第 6 行
  • 我的问题是生成输入字符串的排列。当前删除第一个字母并递归调用该函数,删除最后一个字母并递归调用该函数。
  • @danikitty Max 的第三条建议得到了我的投票。存储字典时,trie 优于集合的好处是,在解析输入字符串时,您会知道何时停止,而使用集合则不可能。您的第二个代码示例显示由于集合的限制,内部循环必须进入输入的全部长度:1)不将您链接到下一个可能的扩展,2)不让您知道是否在终端节点......
猜你喜欢
  • 2014-03-25
  • 1970-01-01
  • 2011-08-28
  • 2020-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-21
  • 2016-04-14
相关资源
最近更新 更多