Анаграммы обнаружитель в JavaScript
Я должен написать программу на JavaScript, чтобы найти все анаграммы в серии слов. например: "монах, konm, нком, Би-би-си, НБР, Делл, ledl, llde" Выходные данные следует классифицировать по строкам: 1. konm монах, нком; 2. Би-би-си "свв"; 3. dell ledl, llde;
Я уже отсортированы в алфавитном порядке, т. е.: "кмно кмно Би-би-си Делл Делл" и сложите их в массив.
однако я застрял в сравнении и поиске соответствующей анаграммы внутри матрица.
любая помощь будет высоко оценили.
13 ответов
объекты Javascript превосходны для этой цели, так как они по существу являются хранилищами ключей/значений:
// Words to match
var words = ["dell", "ledl", "abc", "cba"];
// The output object
var anagrams = {};
for (var i in words) {
var word = words[i];
// sort the word like you've already described
var sorted = sortWord(word);
// If the key already exists, we just push
// the new word on the the array
if (anagrams[sorted] != null) {
anagrams[sorted].push(word);
}
// Otherwise we create an array with the word
// and insert it into the object
else {
anagrams[sorted] = [ word ];
}
}
// Output result
for (var sorted in anagrams) {
var words = anagrams[sorted];
var sep = ",";
var out = "";
for (var n in words) {
out += sep + words[n];
sep = "";
}
document.writeln(sorted + ": " + out + "<br />");
}
вот мое мнение:
var input = "monk, konm, bbc, cbb, dell, ledl";
var words = input.split(", ");
for ( var i = 0; i < words.length; i++) {
var word = words[i];
var alphabetical = word.split("").sort().join("");
for (var j = 0; j < words.length; j++) {
if (i === j) {
continue;
}
var other = words[j];
if(alphabetical === other.split("").sort().join("")){
console.log(word + " - " + other + " (" + i + ", " + j + ")");
}
}
}
где будет вывод (слово, совпадение и индекс обоих):
monk - konm (0, 1)
konm - monk (1, 0)
bbc - cbb (2, 3)
cbb - bbc (3, 2)
dell - ledl (4, 5)
ledl - dell (5, 4)
чтобы получить символы в алфавитном порядке, я использовал split ("") ot получить массив, называемый sort () и использовал join ( "" ), чтобы получить строку из массива.
Я проработал аналогичный вопрос сегодня и хотел поделиться результатами своей работы. Я был сосредоточен только на обнаружении анаграммы, поэтому обработка списка слов не была частью моего упражнения, но этот алгоритм должен обеспечить высокоэффективный способ обнаружения анаграммы между двумя словами.
function anagram(s1, s2){
if (s1.length !== s2.length) {
// not the same length, can't be anagram
return false;
}
if (s1 === s2) {
// same string must be anagram
return true;
}
var c = '',
i = 0,
limit = s1.length,
match = 0,
idx;
while(i < s1.length){
// chomp the next character
c = s1.substr(i++, 1);
// find it in the second string
idx = s2.indexOf(c);
if (idx > -1) {
// found it, add to the match
match++;
// assign the second string to remove the character we just matched
s2 = s2.substr(0, idx) + s2.substr(idx + 1);
} else {
// not found, not the same
return false;
}
}
return match === s1.length;
}
Я думаю, технически это можно решить следующим образом:
function anagram(s1, s2){
return s1.split("").sort().join("") === s2.split("").sort().join("");
}
причина, по которой я выбрал более ранний подход, заключается в том, что он более эффективен для больших строк поскольку вам не нужно сортировать строки, преобразуйте их в массив или цикл по всей строке, если обнаружен какой-либо возможный случай сбоя.
вероятно, не самый эффективный способ, но четкий способ использования es6
function sortStrChars(str) {
if (!str) {
return;
}
str = str.split('');
str = str.sort();
str = str.join('');
return str;
}
const words = ["dell", "ledl", "abc", "cba", 'boo'];
function getGroupedAnagrams(words){
const anagrams = {}; // {abc:[abc,cba], dell:[dell, ledl]}
words.forEach((word)=>{
const sortedWord = sortStrChars(word);
if (anagrams[sortedWord]) {
return anagrams[sortedWord].push(word);
}
anagrams[sortedWord] = [word];
});
return anagrams;
}
const groupedAnagrams = getGroupedAnagrams(words);
for(const sortedWord in groupedAnagrams){
console.log(groupedAnagrams[sortedWord].toString());
}
Я знаю, что это древний пост...но меня только недавно пригвоздили во время интервью по этому поводу. Итак, вот мой новый и улучшенный' ответ:
var AnagramStringMiningExample = function () {
/* Author: Dennis Baughn
* This has also been posted at:
* http://stackoverflow.com/questions/909449/anagrams-finder-in-javascript/5642437#5642437
* Free, private members of the closure and anonymous, innner function
* We will be building a hashtable for anagrams found, with the key
* being the alphabetical char sort (see sortCharArray())
* that the anagrams all have in common.
*/
var dHash = {};
var sortCharArray = function(word) {
return word.split("").sort().join("");
};
/* End free, private members for the closure and anonymous, innner function */
/* This goes through the dictionary entries.
* finds the anagrams (if any) for each word,
* and then populates them in the hashtable.
* Everything strictly local gets de-allocated
* so as not to pollute the closure with 'junk DNA'.
*/
(function() {
/* 'dictionary' referring to English dictionary entries. For a real
* English language dictionary, we could be looking at 20,000+ words, so
* an array instead of a string would be needed.
*/
var dictionaryEntries = "buddy,pan,nap,toot,toto,anestri,asterin,eranist,nastier,ratines,resiant,restain,retains,retinas,retsina,sainter,stainer,starnie,stearin";
/* This could probably be refactored better.
* It creates the actual hashtable entries. */
var populateDictionaryHash = function(keyword, newWord) {
var anagrams = dHash[keyword];
if (anagrams && anagrams.indexOf(newWord) < 0)
dHash[keyword] = (anagrams+','+newWord);
else dHash[keyword] = newWord;
};
var words = dictionaryEntries.split(",");
/* Old School answer, brute force
for (var i = words.length - 1; i >= 0; i--) {
var firstWord = words[i];
var sortedFirst = sortCharArray(firstWord);
for (var k = words.length - 1; k >= 0; k--) {
var secondWord = words[k];
if (i === k) continue;
var sortedSecond = sortCharArray(secondWord);
if (sortedFirst === sortedSecond)
populateDictionaryHash(sortedFirst, secondWord);
}
}/*
/*Better Method for JS, using JS Array.reduce(callback) with scope binding on callback function */
words.reduce(function (prev, cur, index, array) {
var sortedFirst = this.sortCharArray(prev);
var sortedSecond = this.sortCharArray(cur);
if (sortedFirst === sortedSecond) {
var anagrams = this.dHash[sortedFirst];
if (anagrams && anagrams.indexOf(cur) < 0)
this.dHash[sortedFirst] = (anagrams + ',' + cur);
else
this.dHash[sortedFirst] = prev + ','+ cur;
}
return cur;
}.bind(this));
}());
/* return in a nice, tightly-scoped closure the actual function
* to search for any anagrams for searchword provided in args and render results.
*/
return function(searchWord) {
var keyToSearch = sortCharArray(searchWord);
document.writeln('<p>');
if (dHash.hasOwnProperty(keyToSearch)) {
var anagrams = dHash[keyToSearch];
document.writeln(searchWord + ' is part of a collection of '+anagrams.split(',').length+' anagrams: ' + anagrams+'.');
} else document.writeln(searchWord + ' does not have anagrams.');
document.writeln('<\/p>');
};
};
вот как это выполняется:
var checkForAnagrams = new AnagramStringMiningExample();
checkForAnagrams('toot');
checkForAnagrams('pan');
checkForAnagrams('retinas');
checkForAnagrams('buddy');
вот вывод из вышесказанного:
toot является частью коллекции из 2 анаграммы: Тото, тук.
лоток часть собрания 2 анаграммы: сон,Пан.
сетчаток входит в коллекцию из 14 анаграммы: stearin,anestri,asterin,eranist,nastier,ratines,resiant,restain,retains,retinas,retsina,sainter,stainer,starnie.
Бадди не имеет анаграммы.
мое решение для этого старого сообщения:
// Words to match
var words = ["dell", "ledl", "abc", "cba"],
map = {};
//Normalize all the words
var normalizedWords = words.map( function( word ){
return word.split('').sort().join('');
});
//Create a map: normalizedWord -> real word(s)
normalizedWords.forEach( function ( normalizedWord, index){
map[normalizedWord] = map[normalizedWord] || [];
map[normalizedWord].push( words[index] );
});
//All entries in the map with an array with size > 1 are anagrams
Object.keys( map ).forEach( function( normalizedWord , index ){
var combinations = map[normalizedWord];
if( combinations.length > 1 ){
console.log( index + ". " + combinations.join(' ') );
}
});
в основном я нормализую каждое слово, сортируя его символы так stackoverflow будет acefkloorstvw, постройте карту между нормализованными словами и исходными словами, определите, какое нормализованное слово имеет более 1 слова, прикрепленного к нему -> это анаграмма.
У меня был этот вопрос в интервью. Учитывая массив слов ['cat', 'dog', 'tac', 'god', 'act'], верните массив со всеми анаграммами, сгруппированными вместе. Удостоверяется, что анаграммы уникальны.
var arr = ['cat', 'dog', 'tac', 'god', 'act'];
var allAnagrams = function(arr) {
var anagrams = {};
arr.forEach(function(str) {
var recurse = function(ana, str) {
if (str === '')
anagrams[ana] = 1;
for (var i = 0; i < str.length; i++)
recurse(ana + str[i], str.slice(0, i) + str.slice(i + 1));
};
recurse('', str);
});
return Object.keys(anagrams);
}
console.log(allAnagrams(arr));
//["cat", "cta", "act", "atc", "tca", "tac", "dog", "dgo", "odg", "ogd", "gdo", "god"]
может это?
function anagram (array) {
var organized = {};
for (var i = 0; i < array.length; i++) {
var word = array[i].split('').sort().join('');
if (!organized.hasOwnProperty(word)) {
organized[word] = [];
}
organized[word].push(array[i]);
}
return organized;
}
anagram(['kmno', 'okmn', 'omkn', 'dell', 'ledl', 'ok', 'ko']) // Example
он вернет что-то вроде
{
dell: ['dell', 'ledl'],
kmno: ['kmno', okmn', 'omkn'],
ko: ['ok', ko']
}
это простая версия того, что вы хотели, и, конечно, это может быть улучшено, избегая дубликатов, например.
function isAnagram(str1, str2) {
var str1 = str1.toLowerCase();
var str2 = str2.toLowerCase();
if (str1 === str2)
return true;
var dict = {};
for(var i = 0; i < str1.length; i++) {
if (dict[str1[i]])
dict[str1[i]] = dict[str1[i]] + 1;
else
dict[str1[i]] = 1;
}
for(var j = 0; j < str2.length; j++) {
if (dict[str2[j]])
dict[str2[j]] = dict[str2[j]] - 1;
else
dict[str2[j]] = 1;
}
for (var key in dict) {
if (dict[key] !== 0)
return false;
}
return true;
}
console.log(isAnagram("hello", "olleh"));
у меня есть простой пример
function isAnagram(strFirst, strSecond) {
if(strFirst.length != strSecond.length)
return false;
var tempString1 = strFirst.toLowerCase();
var tempString2 = strSecond.toLowerCase();
var matched = true ;
var cnt = 0;
while(tempString1.length){
if(tempString2.length < 1)
break;
if(tempString2.indexOf(tempString1[cnt]) > -1 )
tempString2 = tempString2.replace(tempString1[cnt],'');
else
return false;
cnt++;
}
return matched ;
}
вызывающая функция будет isAnagram("Army",Mary);
Функция будет возвращать true
или false
другое решение для isAnagram с использованием reduce
const checkAnagram = (orig, test) => {
return orig.length === test.length
&& orig.split('').reduce(
(acc, item) => {
let index = acc.indexOf(item);
if (index >= 0) {
acc.splice(index, 1);
return acc;
}
throw new Error('Not an anagram');
},
test.split('')
).length === 0;
};
const isAnagram = (tester, orig, test) => {
try {
return tester(orig, test);
} catch (e) {
return false;
}
}
console.log(isAnagram(checkAnagram, '867443', '473846'));
console.log(isAnagram(checkAnagram, '867443', '473846'));
console.log(isAnagram(checkAnagram, '867443', '475846'));
var check=true;
var str="cleartrip";
var str1="tripclear";
if(str.length!=str1.length){
console.log("Not an anagram");
check=false;
}
console.log(str.split("").sort());
console.log("----------"+str.split("").sort().join(''));
if(check){
if((str.split("").sort().join(''))===((str1.split("").sort().join('')))){
console.log("Anagram")
}
else{
console.log("not a anagram");
}
}
Простое Решение
function anagrams(stringA, stringB) {
return cleanString(stringA) === cleanString(stringB);
}
function cleanString(str) {
return str.replace(/[^\w]/g).toLowerCase().split('').sort().join()
}
anagrams('monk','konm')
Если это анаграммы функция вернет true иначе false