-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathanagram-finder.js
108 lines (98 loc) · 3.82 KB
/
anagram-finder.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/* prototype extensions */
String.prototype.removeCharAt = function (i) {
if (i < 0 || i > this.length) {
throw 'Index out of range: ' + i + '. Length of string: ' + this.length;
}
return this.slice(0, i) + this.slice(i + 1);
}
String.prototype.toAnagramKey = function () {
// return characters in alphabetical order
return this.split('').sort().join('');
}
Array.prototype.distinct = function () {
var a = [];
for (var i = 0, l = this.length; i < l; i++)
if (a.indexOf(this[i]) === -1)
a.push(this[i]);
return a;
}
var AnagramFinder = function (words) {
var alphabet = 'abcdefghijklmnopqrstuvwxyz';
var anagramDictionary = createAnagramDictionary(words);
function createAnagramDictionary(words) {
var dictionary = new Map();
for (var i = 0; i < words.length; i++) {
var word = words[i];
var key = word.toAnagramKey();
if (!dictionary.has(key)) {
dictionary.set(key, [word]);
}
else {
dictionary.get(key).push(word);
}
}
return dictionary;
}
this.findAnagrams = function (letters, numberOfExtraLetters = 0) {
if (numberOfExtraLetters == 0) {
var key = letters.toAnagramKey();
return anagramDictionary.get(key) || [];
}
var allAnagrams = [];
for (var i = 0; i < alphabet.length; i++) {
var letter = alphabet.charAt(i);
var newLetters = letters + letter;
var anagrams = this.findAnagrams(newLetters, numberOfExtraLetters - 1);
allAnagrams = allAnagrams.concat(anagrams);
}
return allAnagrams.distinct().sort();
}
function getAllSubsetsOfLetters(letters) {
var key = letters.toAnagramKey();
var subsets = [];
// e.g. key.length = 4: 1111, 1110, 1101, 1100, ... 11, 10, 1.
for (var i = Math.pow(2, key.length) - 1; i >= 1; i--) {
var set = '';
var binaryString = i.toString(2);
// pad out left, so if key.length = 4, we treat 10 as 0010
var paddingOffset = key.length - binaryString.length;
for (var j = 0; j < key.length; j++) {
if (binaryString[j] === '1') {
set += key[j + paddingOffset];
}
}
subsets.push(set);
}
// distinct because duplicate letters will create sets
return subsets.distinct();
}
this.findLongestWords = function (letters, maxNumberOfExtraLetters = 1) {
var subsetsOfLetters = getAllSubsetsOfLetters(letters);
var currentLengthToTest = letters.length;
var words = [];
while (words.length === 0 && currentLengthToTest > 0) {
for (var i = 0; i < subsetsOfLetters.length; i++) {
if (subsetsOfLetters[i].length === currentLengthToTest) {
for (var numberOfExtraLetters = maxNumberOfExtraLetters; numberOfExtraLetters >= 0; numberOfExtraLetters--) {
var anagrams = this.findAnagrams(subsetsOfLetters[i], numberOfExtraLetters);
words = words.concat(anagrams);
}
}
}
currentLengthToTest--;
}
return words.distinct();
}
this.findCrosswordAnswers = function (lettersWithBlanks) {
var results = [];
var regex = new RegExp('^' + lettersWithBlanks.replace(/\?/g, '.') + '$');
for (var i = 0; i < words.length; i++) {
var word = words[i];
var match = regex.exec(word);
if (match) {
results.push(word);
}
}
return results;
}
}