|
1 | 1 | /**
|
2 |
| - * @param {string} s |
3 |
| - * @param {string} p |
4 |
| - * @return {number[]} |
| 2 | + * @param {string} stream Input string. |
| 3 | + * @param {string} word Word to compare substring to. |
| 4 | + * @return {number[]} Array with indexes of all substrings that are anagrams of word. |
| 5 | + * @summary Find All Anagrams in a String {@link https://leetcode.com/problems/find-all-anagrams-in-a-string/} |
| 6 | + * @description Given two input strings return indexes of substrings that are anagrams of second input. |
| 7 | + * Space O(A+B) - A length of string 'word', B length of string 'stream'. |
| 8 | + * Time O(1) - Two new arrays, each of 26 elements. |
5 | 9 | */
|
| 10 | +const findAnagrams = (stream, word) => { |
| 11 | + const counts = Array(26); |
| 12 | + const currentCount = Array(26); |
| 13 | + const offset = 'a'.charCodeAt(); |
| 14 | + const answer = []; |
| 15 | + const sLength = stream.length; |
| 16 | + const wLength = word.length; |
6 | 17 |
|
7 |
| -const isAnagram = (word, candidate) => { |
8 |
| - if (word.length !== candidate.length) return false; |
| 18 | + for (let i = 0; i < wLength; i++) { |
| 19 | + const index = word[i].charCodeAt() - offset; |
9 | 20 |
|
10 |
| - const charMap = {}; |
11 |
| - for (let index = 0; index < word.length; index++) { |
12 |
| - if (word.indexOf(candidate[index]) < 0) { |
13 |
| - return false; |
14 |
| - } |
15 |
| - charMap[word[index]] = charMap[word[index]] ? charMap[word[index]] + 1 : 1; |
16 |
| - charMap[candidate[index]] = charMap[candidate[index]] ? charMap[candidate[index]] - 1 : -1; |
| 21 | + counts[index] = counts[index] ? counts[index] + 1 : 1; |
17 | 22 | }
|
18 | 23 |
|
19 |
| - return Object.keys(charMap).every(char => charMap[char] === 0); |
20 |
| -}; |
21 |
| - |
22 |
| -const findAnagrams = (s, p) => { |
23 |
| - const anagrams = {}; |
24 |
| - anagrams[p] = true; |
| 24 | + for (let i = 0; i < sLength; i++) { |
| 25 | + const index = stream[i].charCodeAt() - offset; |
25 | 26 |
|
26 |
| - const answer = []; |
27 |
| - |
28 |
| - const length = s.length - p.length + 1; |
29 |
| - for (let index = 0; index < length; index++) { |
30 |
| - const candidate = s.slice(index, index + p.length); |
| 27 | + currentCount[index] = currentCount[index] ? currentCount[index] + 1 : 1; |
31 | 28 |
|
32 |
| - if (anagrams[candidate] === undefined) anagrams[candidate] = isAnagram(p, candidate); |
| 29 | + if (i >= wLength) { |
| 30 | + const index = stream[i - wLength].charCodeAt() - offset; |
| 31 | + currentCount[index] = currentCount[index] ? currentCount[index] - 1 : undefined; |
| 32 | + } |
33 | 33 |
|
34 |
| - if (anagrams[candidate]) answer.push(index); |
| 34 | + if (counts.every((count, index) => count === currentCount[index])) { |
| 35 | + answer.push(i - wLength + 1); |
| 36 | + } |
35 | 37 | }
|
36 | 38 |
|
37 | 39 | return answer;
|
|
0 commit comments