Skip to content

Commit faa77a4

Browse files
authored
Merge pull request #404 from sir-gon/feature/sherlock_and_anagrams
Feature/sherlock and anagrams
2 parents 7720186 + 09517b8 commit faa77a4

File tree

3 files changed

+227
-0
lines changed

3 files changed

+227
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# [Sherlock and Anagrams](https://www.hackerrank.com/challenges/sherlock-and-anagrams)
2+
3+
- Difficulty: `#medium`
4+
- Category: `#ProblemSolvingMedium` `#DictionariesAndHashmaps` `#Strings`
5+
6+
Two strings are [http://en.wikipedia.org/wiki/Anagram](anagrams) of each other
7+
if the letters of one string can be rearranged to form the other string.
8+
Given a string, find the number of pairs of substrings of the string that are
9+
anagrams of each other.
10+
11+
## Example
12+
13+
`s = mom`
14+
15+
The list of all anagrammatic pairs is `[m, m]`, `[mo, om]`
16+
at positions `[[0], [2]]`, `[[0, 1], [1, 2]]` respectively.
17+
18+
## Function Description
19+
20+
Complete the function sherlockAndAnagrams in the editor below.
21+
22+
*sherlockAndAnagrams* has the following parameter(s):
23+
24+
- `string s`: a string
25+
26+
## Returns
27+
28+
- `int`: the number of unordered anagrammatic pairs of substrings in **`s`**
29+
30+
## Input Format
31+
32+
The first line contains an integer `q`, the number of queries.
33+
Each of the next `q` lines contains a string `s` to analyze.
34+
35+
## Constraints
36+
37+
- $ 1 \leq 10 \leq 10 $
38+
- $ 2 \leq $ lenght of `s` $ \leq 100 $
39+
40+
`s` contains only lowercase letters in the range ascii[a-z].
41+
42+
## Sample Input 0
43+
44+
```text
45+
2
46+
abba
47+
abcd
48+
```
49+
50+
## Sample Output 0
51+
52+
```text
53+
4
54+
0
55+
```
56+
57+
## Explanation 0
58+
59+
The list of all anagrammatic pairs is `[a, a]`, `[ab, ba]`,
60+
`[b, b]` and `[abb, bba]` at positions `[[0], [3]]`, `[[0, 1]], [[2, 3]]`,
61+
`[[1], [2]]` and `[[0, 1, 2], [1, 2, 3]]` respectively.
62+
63+
No anagrammatic pairs exist in the second query as no character repeats.
64+
65+
## Sample Input 1
66+
67+
```text
68+
2
69+
ifailuhkqq
70+
kkkk
71+
````
72+
73+
## Sample Output 1
74+
75+
```text
76+
3
77+
10
78+
```
79+
80+
## Explanation 1
81+
82+
For the first query, we have anagram pairs `[i, i]`, `[q, q]`
83+
and `[ifa, fai]` at positions `[[0], [3]]`, `[[8], [9]]`
84+
and `[[0, 1, 2], [1, 2, 3]]` respectively.
85+
86+
For the second query:
87+
88+
There are `6` anagrams of the form `[k, k]` at positions `[[0, 1]]`,
89+
`[[0], [2]]`, `[[0], [3]]`, `[[1], [2]]`, `[[1], [3]]` and `[[2], [3]]`.
90+
91+
There are 3 anagrams of the form `[kk, kk]` at positions `[[0, 1], [1, 2]]`,
92+
`[[0, 1], [2, 3]]` and `[[1, 2], [2, 3]]`.
93+
94+
There is 1 anagram of the form `[kkk, kkk]` at position `[[0, 1, 2], [1, 2, 3]]`.
95+
96+
## Sample Input 2
97+
98+
```text
99+
1
100+
cdcd
101+
```
102+
103+
## Sample Output 2
104+
105+
```text
106+
5
107+
```
108+
109+
## Explanation 2
110+
111+
There are two anagrammatic pairs of length `1`: `[c, c]` and `[d, d]`.
112+
There are three anagrammatic pairs of length `2`:
113+
`[cd, dc]`, `[cd, cd]`, `[dc, cd]` at positions
114+
`[[0, 1] [1, 2]]`, `[[0, 1], [2, 3]]`, `[1, 2], [2, 3]` respectively.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { describe, expect, it } from '@jest/globals';
2+
import { logger as console } from '../../../logger';
3+
4+
import { sherlockAndAnagrams } from './sherlock_and_anagrams';
5+
6+
const TEST_CASES = [
7+
{
8+
title: 'Sample Test Case 0',
9+
tests: [
10+
{
11+
input: 'abba',
12+
expected: 4
13+
},
14+
{
15+
input: 'abcd',
16+
expected: 0
17+
}
18+
]
19+
},
20+
{
21+
title: 'Sample Test Case 1',
22+
tests: [
23+
{
24+
input: 'ifailuhkqq',
25+
expected: 3
26+
},
27+
{
28+
input: 'kkkk',
29+
expected: 10
30+
}
31+
]
32+
},
33+
{
34+
title: 'Sample Test Case 1',
35+
tests: [
36+
{
37+
input: 'cdcd',
38+
expected: 5
39+
}
40+
]
41+
}
42+
];
43+
44+
describe('sherlock_and_anagrams', () => {
45+
it('sherlockAndAnagrams test cases', () => {
46+
expect.assertions(5);
47+
48+
TEST_CASES.forEach((testSet) => {
49+
testSet.tests.forEach((test) => {
50+
const answer = sherlockAndAnagrams(test.input);
51+
52+
console.debug(`checkMagazine(${test.input}) solution found: ${answer}`);
53+
54+
expect(answer).toStrictEqual(test.expected);
55+
});
56+
});
57+
});
58+
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @link Problem definition [[docs/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/sherlock_and_anagrams.md]]
3+
*/
4+
5+
function factorial(n: number): number {
6+
if (n == 0) {
7+
return 1;
8+
}
9+
return n * factorial(n - 1);
10+
}
11+
12+
export function sherlockAndAnagrams(s: string): number {
13+
const candidates: Record<string, string[]> = {};
14+
const size = s.length;
15+
16+
for (let i = 0; i < size; i++) {
17+
for (let j = 0; j < size - i; j++) {
18+
const substr = s.substring(i, size - j);
19+
20+
// Add substrings to a candidate list.
21+
// two strings are anagrams if sorted strings are the same.
22+
23+
const anagram_candidate = substr
24+
.split('')
25+
.sort((a: string, b: string) => a.localeCompare(b))
26+
.join('');
27+
if (anagram_candidate in candidates) {
28+
candidates[anagram_candidate].push(substr);
29+
} else {
30+
candidates[anagram_candidate] = [substr];
31+
}
32+
}
33+
}
34+
35+
let count = 0;
36+
// Final Anagram list
37+
for (const i of Object.keys(candidates)) {
38+
const total = candidates[i].length;
39+
const k = 2;
40+
41+
if (total <= 1) {
42+
delete candidates[i];
43+
} else {
44+
// Binomial coefficient: https://en.wikipedia.org/wiki/Binomial_coefficient
45+
count += Math.floor(
46+
factorial(total) / (factorial(k) * factorial(total - k))
47+
);
48+
}
49+
}
50+
console.debug(`filtered candidates: ${count}`);
51+
52+
return count;
53+
}
54+
55+
export default { sherlockAndAnagrams };

0 commit comments

Comments
 (0)