Проблема: учитывая два массива строк, для каждой строки в списке (запросе) определите, сколько ее анаграмм находится в другом списке (словаре). Он должен возвращать массив целых чисел. Пример: query = [& ...

1
Vicky 17 Янв 2021 в 02:18

3 ответа

Лучший ответ

Возможно, вы захотите избежать использования (дорогостоящего) 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)
1
Yevgen Gorbunkov 16 Янв 2021 в 23:41

Итак, если я правильно понимаю, строки 'aab', 'baa', 'aba' являются анаграммами?

Вместо того, чтобы сортировать их, я бы попытался создать дешевую и быструю подпись.

Если мы преобразуем каждый символ в его код ascii и просуммируем их все, то каждая строка выдаст одно и то же число:

const sum_str = str => str.split('').reduce((n, c) n + c.charCodeAt(0), 0);

sum_str('aab'); //=> 292
sum_str('baa'); //=> 292
sum_str('aba'); //=> 292

Теперь все, что вам нужно сделать, это преобразовать query и dictionary в массивы чисел и посчитать, сколько раз каждое число из одного массива встречается в другом:

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

const sum_str = str => str.split('').reduce((n, c) => n + c.charCodeAt(0), 0);

const count_anagrams = (qry, dic) => {
  const qry_sum = qry.map(sum_str);
  const dic_sum = dic.map(sum_str);
  return qry_sum.map(q => dic_sum.filter(d => d === q).length);
}

count_anagrams(qry, dic);
//=> [2, 2, 0, 3, 1]

Однако у этого метода есть одна большая оговорка. Должна быть возможность получить две строки, например sum_str(a) === sum_str(b) истинно, но две строки не анаграммы.

0
customcommander 17 Янв 2021 в 01:09

Чуть более подробный способ сделать это - но для меня он работает и имеет смысл - для каждого слова в исходном массиве найдите слова в целевом массиве одинаковой длины, а затем подсчитайте те, которые являются анаграммами исходного слова ( анаграмма - это другое слово, состоящее из тех же букв в любом порядке).

Итак, шаги -

Перебрать первый массив и для каждого слова - отфильтровать целевой массив, чтобы получить все слова той же длины, что и это слово (потенциальные анаграммы)

Затем переберите этот массив possibleAnagrams и передайте каждое слово функции, которая проверяет, присутствуют ли все буквы и только буквы в исходном слове (в данном примере - это будет [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('');
  word1Arr.forEach(function(letter){
    if(word2.indexOf(letter) !== -1) {
     count++
    }
  })
    return count === word1Arr.length
}

console.log(anagramsArr); //gives [2, 2, 0, 3,1];
0
gavgrif 17 Янв 2021 в 06:53
65755710