Skip to content

[Hacker Rank] Interview Preparation Kit: Dictionaries and Hashmaps: S… #192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# [Sherlock and Anagrams](https://www.hackerrank.com/challenges/sherlock-and-anagrams)

- Difficulty: `#medium`
- Category: `#ProblemSolvingMedium` `#DictionariesAndHashmaps` `#Strings`

## About solution

To answer the question of "how many pairs" of words can be anagrammed
using fragments from adjacent letters of an initial word, two steps are needed:

1) Obtain all possible fragment candidates to be anagrams,
from each of the possible fragments that can be generated
from adjacent letters of a word.

2) For each list of candidate anagrams,
calculate all possible permutations and add them up.
The total gives the answer.

The second part of this problem can be solved with the binomial coefficient formula:

<https://en.wikipedia.org/wiki/Binomial_coefficient>

But the entire cost of this formula falls on the "factorial" function.

The factorial quickly reaches results that return large numbers,
overflowing the length of primitive number types.

To avoid this problem in C#, it is necessary to introduce large number handling
using System.Numerics.BigInteger
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# [Sherlock and Anagrams](https://www.hackerrank.com/challenges/sherlock-and-anagrams)

- Difficulty: `#medium`
- Category: `#ProblemSolvingMedium` `#DictionariesAndHashmaps` `#Strings`

Two strings are [http://en.wikipedia.org/wiki/Anagram](anagrams) of each other
if the letters of one string can be rearranged to form the other string.
Given a string, find the number of pairs of substrings of the string that are
anagrams of each other.

## Example

`s = mom`

The list of all anagrammatic pairs is `[m, m]`, `[mo, om]`
at positions `[[0], [2]]`, `[[0, 1], [1, 2]]` respectively.

## Function Description

Complete the function sherlockAndAnagrams in the editor below.

*sherlockAndAnagrams* has the following parameter(s):

- `string s`: a string

## Returns

- `int`: the number of unordered anagrammatic pairs of substrings in **`s`**

## Input Format

The first line contains an integer `q`, the number of queries.
Each of the next `q` lines contains a string `s` to analyze.

## Constraints

- $ 1 \leq 10 \leq 10 $
- $ 2 \leq $ lenght of `s` $ \leq 100 $

`s` contains only lowercase letters in the range ascii[a-z].

## Sample Input 0

```text
2
abba
abcd
```

## Sample Output 0

```text
4
0
```

## Explanation 0

The list of all anagrammatic pairs is `[a, a]`, `[ab, ba]`,
`[b, b]` and `[abb, bba]` at positions `[[0], [3]]`, `[[0, 1]], [[2, 3]]`,
`[[1], [2]]` and `[[0, 1, 2], [1, 2, 3]]` respectively.

No anagrammatic pairs exist in the second query as no character repeats.

## Sample Input 1

```text
2
ifailuhkqq
kkkk
````

## Sample Output 1

```text
3
10
```

## Explanation 1

For the first query, we have anagram pairs `[i, i]`, `[q, q]`
and `[ifa, fai]` at positions `[[0], [3]]`, `[[8], [9]]`
and `[[0, 1, 2], [1, 2, 3]]` respectively.

For the second query:

There are `6` anagrams of the form `[k, k]` at positions `[[0, 1]]`,
`[[0], [2]]`, `[[0], [3]]`, `[[1], [2]]`, `[[1], [3]]` and `[[2], [3]]`.

There are 3 anagrams of the form `[kk, kk]` at positions `[[0, 1], [1, 2]]`,
`[[0, 1], [2, 3]]` and `[[1, 2], [2, 3]]`.

There is 1 anagram of the form `[kkk, kkk]` at position `[[0, 1, 2], [1, 2, 3]]`.

## Sample Input 2

```text
1
cdcd
```

## Sample Output 2

```text
5
```

## Explanation 2

There are two anagrammatic pairs of length `1`: `[c, c]` and `[d, d]`.
There are three anagrammatic pairs of length `2`:
`[cd, dc]`, `[cd, cd]`, `[dc, cd]` at positions
`[[0, 1] [1, 2]]`, `[[0, 1], [2, 3]]`, `[1, 2], [2, 3]` respectively.
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// @link Problem definition [[docs/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/ctci-ransom-note.md]]

namespace algorithm_exercises_csharp.hackerrank.interview_preparation_kit.dictionaries_and_hashmaps;

using System.Diagnostics.CodeAnalysis;
using System.Numerics;

public class SherlockAndAnagrams
{
[ExcludeFromCodeCoverage]
protected SherlockAndAnagrams() { }

/**
* factorial().
*/
public static BigInteger factorial(int number)
{
BigInteger result = BigInteger.One;
for (int i = 1; i <= number; i++)
{
result *= i;
}

return result;
}

public static int sherlockAndAnagrams(string s)
{
Dictionary<string, List<string>> candidates = [];

int size = s.Length;
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size - i; j++)
{
string word = s[i..(size - j)];
char[] wordArray = word.ToCharArray();
Array.Sort(wordArray);
string anagramCandidate = new(wordArray);

if (candidates.TryGetValue(anagramCandidate, out List<string>? value))
{
value.Add(word);
}
else
{
candidates[anagramCandidate] = [word];
}
}
}

int k = 2;

int total = candidates
.Select(x => x.Value.Count)
.Where(count => count > 1)
.Sum(quantityOfAnagrams =>
// Binomial coefficient: https://en.wikipedia.org/wiki/Binomial_coefficient
(int)(factorial(quantityOfAnagrams) / factorial(k) / factorial(quantityOfAnagrams - k)));

return total;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
[
{
"title": "Sample Test Case 0",
"tests": [
{
"input": "abba",
"expected": 4
},
{
"input": "abcd",
"expected": 0
}
]
},
{
"title": "Sample Test Case 1",
"tests": [
{
"input": "ifailuhkqq",
"expected": 3
},
{
"input": "kkkk",
"expected": 10
}
]
},
{
"title": "Sample Test Case 1",
"tests": [
{
"input": "cdcd",
"expected": 5
}
]
},
{
"title": "Test case 3",
"tests": [
{
"input":
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"expected": 166650
},
{
"input":
"bbcaadacaacbdddcdbddaddabcccdaaadcadcbddadababdaaabcccdcdaacadcababbabbdbacabbdcbbbbbddacdbbcdddbaaa",
"expected": 4832
},
{
"input":
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"expected": 166650
},
{
"input":
"cacccbbcaaccbaacbbbcaaaababcacbbababbaacabccccaaaacbcababcbaaaaaacbacbccabcabbaaacabccbabccabbabcbba",
"expected": 13022
},
{
"input":
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"expected": 166650
},
{
"input":
"bbcbacaabacacaaacbbcaabccacbaaaabbcaaaaaaaccaccabcacabbbbabbbbacaaccbabbccccaacccccabcabaacaabbcbaca",
"expected": 9644
},
{
"input":
"cbaacdbaadbabbdbbaabddbdabbbccbdaccdbbdacdcabdbacbcadbbbbacbdabddcaccbbacbcadcdcabaabdbaacdccbbabbbc",
"expected": 6346
},
{
"input":
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"expected": 166650
},
{
"input":
"babacaccaaabaaaaaaaccaaaccaaccabcbbbabccbbabababccaabcccacccaaabaccbccccbaacbcaacbcaaaaaaabacbcbbbcc",
"expected": 8640
},
{
"input":
"bcbabbaccacbacaacbbaccbcbccbaaaabbbcaccaacaccbabcbabccacbaabbaaaabbbcbbbbbaababacacbcaabbcbcbcabbaba",
"expected": 11577
}
]
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace algorithm_exercises_csharp_test.hackerrank.interview_preparation_kit.dictionaries_and_hashmaps;
using algorithm_exercises_csharp_test.lib;
using algorithm_exercises_csharp.hackerrank.interview_preparation_kit.dictionaries_and_hashmaps;

[TestClass]
public class SherlockAndAnagramsTest
{
public class SherlockAndAnagramsTestCase
{
/**
* SherlockAndAnagramsTestCase.TestCase.
*/
public class TestCase
{
public string input { get; set; } = default!;
public int expected { get; set; } = default!;
}

public string title { get; set; } = default!;
public List<TestCase> tests { get; set; } = default!;
}

private List<SherlockAndAnagramsTestCase> testCases { get; set; } = default!;

[TestInitialize]
public void testInitialize()
{
testCases = JsonLoader.resourceLoad<List<SherlockAndAnagramsTestCase>>(
"hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/sherlock_and_anagrams.testcases.json"
) ?? [];
}

[TestMethod]
public void testSherlockAndAnagrams()
{
int result;

foreach (SherlockAndAnagramsTestCase testSet in testCases)
{
foreach (SherlockAndAnagramsTestCase.TestCase test in testSet.tests)
{
result = SherlockAndAnagrams.sherlockAndAnagrams(test.input);
Assert.AreEqual(test.expected, result);
}
}
}
}