Javascript - 查找字谜的更好解决方案 - 时间复杂度 O (n log n)

Posted

技术标签:

【中文标题】Javascript - 查找字谜的更好解决方案 - 时间复杂度 O (n log n)【英文标题】:Javascript - Better solution for finding anagrams - Time complexity O (n log n) 【发布时间】:2019-09-13 07:21:51 【问题描述】:

免责声明

大家好,我知道很少有 javascript 问题/答案可以解决如何查找两个单词是否是字谜。

我不只是在寻找一个函数来确定两个单词/字符串是否是字谜。我正在寻找一种比下面提供的更快的功能。目前,我认为下面函数的时间复杂度是O (n log n)

我想找出一个时间复杂度为 O(n) 的函数,或者一个运行时间比提供的更快的函数。

代码

const isAnagram = (str1, str2) => 

  str1 = str1.toLowerCase();
  str2 = str2.toLowerCase();


  if (str1.length !== str2.length) 
     return false
  

  let sortStr1 = str1.split('').sort().join('').trim();
  let sortStr2 = str2.split('').sort().join('').trim();

  return sortStr1 === sortStr2
 ;

console.log(isAnagram('dog', 'goD')); //true

【问题讨论】:

使用O(n)排序,你的代码是O(n)。顺便说一句,您尝试了什么:/ 对不起,我不确定你的意思 像en.wikipedia.org/wiki/Counting_sort 这样的东西确实给你O(n) 排序复杂性。 所以你是说我的方法确实返回了 O(n) 的时间复杂度? 是的,如果你使用O(n)排序方法。 【参考方案1】:

您可以尝试基于计数的算法。

const isAnagram = (str1, str2) => 

  str1 = str1.toLowerCase();
  str2 = str2.toLowerCase();
  //and remove any char you think not important (like space) here
  
  if (str1.length !== str2.length) return false
  
  let counting = 
  for(let c of str1) 
     if(counting[c]) ++counting[c]
     else counting[c] = 1
  
  for(let c of str2)
     if(counting[c]) --counting[c]
     else return false
  
  return true
;

console.log(isAnagram('dog', 'goD')); //true
console.log(isAnagram('eleven plus two', 'twelve plus one')); //true
console.log(isAnagram('dog', 'hot')); //false
console.log(isAnagram('banana', 'nana')); //false

【讨论】:

我相信这会给我们一个 O(n^2) 的时间复杂度? @mph85 为什么?你从哪里得到的? 不是我的错,我以为它是嵌套的,但它不是 if 语句中发生了什么? if(counting[c]) --counting[c] 这是什么意思?以及以下else counting[c] = 1? @mph85 第一个if(counting[c]) 表示if(c in counting),第二个if(counting[c]) 表示if(c in counting && c != 0)【参考方案2】:

这是另一个可能的想法,来自:An Algorithm for Finding Anagrams,它基于 fundamental theorem of arithmetic 声明:

每个大于1 的整数要么是素数本身,要么可以表示为素数的乘积,而且这种表示是唯一的,直到(除了)因子的顺序。

因此,如果我们将字母表中的每个字母分配给一个素数,然后计算这些数字的乘积,这个数字将是唯一的( 因为算术基本定理)。这意味着对于多组字母,该多组中每个字母的素数乘积是唯一的。那么,如果两个单词或句子有相同的数字,这两个单词或句子是彼此的字谜。

实施:

let letters = "a":2, "b":3, "c":5, "d":7, "e":11, "f":13, "g":17, "h":19, "i":23, "j":29, "k":31, "l":37, "m":41, "n":43, "o":47, "p":53, "q":59, "r":61, "s":67, "t":71, "u":73, "v":79, "w":83, "x":89, "y":97, "z":101;

const isAnagram = (str1, str2) =>

    str1 = str1.toLowerCase();
    str2 = str2.toLowerCase();            
    let repStr1 = 1, repStr2 = 1;

    for (let i = 0; i < Math.max(str1.length, str2.length); i++)
    
        repStr1 *= (str1[i] && letters[str1[i]]) ? letters[str1[i]] : 1;
        repStr2 *= (str2[i] && letters[str2[i]]) ? letters[str2[i]] : 1;
    

    return (repStr1 === repStr2);
;

console.log("[dog, goD] Anagrams?", isAnagram('dog', 'goD'));
console.log("[dogo, goD] Anagrams?", isAnagram('dogo', 'goD')); 
console.log("[Roast Beef, Eat for BSE] Anagrams?", isAnagram('Roast Beef', 'Eat for BSE'));
.as-console background-color:black !important; color:lime;
.as-console-wrapper max-height:100% !important; top:0;

优势

接受不同长度的字谜(查看第三个示例)。 是O(n)(只需要一个循环)。

缺点

不适用于大型表达式,生成的数字会溢出。 需要一个预定义的字母和引物编号之间的字典。 不适用于包含稀有字符的表达式,除非您扩展字典,但溢出会变得更加频繁。

【讨论】:

我认为这是回文,而不是字谜?

以上是关于Javascript - 查找字谜的更好解决方案 - 时间复杂度 O (n log n)的主要内容,如果未能解决你的问题,请参考以下文章

查找字谜 JavaScript jQuery

javascript [438。查找字符串中的所有字谜] #tags:leetcode

在 Javascript 中使用 Map 从一组字谜中查找唯一单词

做字谜组的更好方法

正则表达式 - 查找字谜和子字谜

使用python中的递归解决方案在字符串列表中查找字谜