快速字谜检查算法 (HackerRank)

Fast anagrams checker algorithm (HackerRank)

问题:

给定两个字符串数组,对于列表(查询)中的每个字符串,确定它在另一个列表(字典)中有多少个字谜。 它应该 return 一个整数数组。

示例:

query = ["a", "nark", "bs", "hack", "stair"]
dictionary = ['hack', 'a', 'rank', 'khac', 'ackh', 'kran', 'rankhacker', 'a', 'ab', 'ba', 'stairs', 'raits']

答案是 [2, 2, 0, 3, 1],因为 query[0] ('a') 在 dictionary 中有 2 个字谜:'a' 和 'a' 等等在...

这是我想出的代码:

function sortArray(array) {
    let answer = [];
    for(let i = 0; i< array.length ; i++) {
         let data = array[i].split('').sort().join('');
         answer.push(data);
    }
    return answer;
}

function stringAnagram(dictionary, query) {
    // Write your code here
    let sortedDict = sortArray(dictionary);
    let sortedQuery = sortArray(query);
    let answer = [];
    console.log(sortedDict.length);
    console.log(sortedQuery.length);
    sortedQuery.map(data => {
        let i = 0;
        sortedDict.forEach(dictData => {
            if(data === dictData)
                i++;
        })
        answer.push(i);
    })

    return answer;
}

然而,对于较长的测试用例,它是 returning 超时错误。需要一些帮助来优化它。有什么建议么?我正在努力在 JavaScript.

中实现它

您可能希望避免使用(昂贵的)Array.prototype.sort() 来检测变位词,并为您的变位词检测算法提供尽可能多的快捷方式。

因此,如果假设变位词应该是具有相同字符数的相同长度的字符串,您可以这样做:

const  query = ["a", "nark", "bs", "hack", "stair"], 
        dictionary = ['hack', 'a', 'rank', 'khac', 'ackh', 'kran', 'rankhacker', 'a', 'ab', 'ba', 'stairs', 'raits'],
        
        charCount = s => [...s].reduce((acc,c) => 
          (acc[c]=(acc[c]||0)+1, acc), {}),
          
        areAnagrams = (s1, s2) => {
          if(s1.length != s2.length) return false
          const s1CharCount = charCount(s1),
                s2CharCount = charCount(s2),
                result = Object
                  .keys(s1CharCount)
                  .every(char =>
                    s2CharCount[char] == s1CharCount[char])
          return result
        },
        
        outcome = query.map(word =>
          dictionary
            .filter(_word => areAnagrams(word, _word))
            .length
        )
            
console.log(outcome)

稍微更冗长的方法 - 但它有效并且对我有意义 - 对于原始数组中的每个单词,找到目标数组中长度相同的单词,然后计算那些是原始单词(变位词是由相同字母以任意顺序组成的另一个单词)。

所以步骤是-

迭代 firat 数组并针对每个单词 - 过滤目标数组以获得与该单词长度相同的所有单词(potentialAnagrams)

然后遍历 potentialAnagrams 数组并将每个单词传递给一个函数,该函数检查是否存在所有字母并且仅存在原始单词中的字母(在给定的示例中 - 即 [2, 2, 0, 3, 1]

将单词的所有字谜相加,并将计数传递给记录为最终结果的数组。

const  queryArr = ["a", "nark", "bs", "hack", "stair"];
const dictionaryArr = ['hack', 'a', 'rank', 'khac', 'ackh', 'kran', 'rankhacker', 'a', 'ab', 'ba', 'stairs', 'raits'];

let anagramsArr = [];

queryArr.forEach(function(query){
  let anagramsCount = 0
  const potentialAnagrams = dictionaryArr.filter(el => el.length === query.length);

  potentialAnagrams.forEach(function(potentialAnagram){
     if(isAnagram(query,potentialAnagram)){
      anagramsCount++
     }
   })
  anagramsArr.push(anagramsCount);
})

function isAnagram(word1, word2){
  let count = 0;
  const word1Arr = word1.split('');
  const word2Arr = word2.split('');
  
  if( word1Arr.length !== word2Arr.length) {
     return 'Invalid data - words 1 and 2 are of different lengths';
  }
  
  word1Arr.forEach(function(letter){
    if(word2.indexOf(letter) !== -1) {
     count++
    }
  })
    return count === word1Arr.length
}
console.log(isAnagram('ab', 'bab')); //gives 'Invalid data - words 1 and 2 are of different lengths';

console.log(anagramsArr); //gives [2, 2, 0, 3,1];