diff --git a/algorithm-exercises-java/src/main/java/ae/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/RansomNote.java b/algorithm-exercises-java/src/main/java/ae/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/RansomNote.java new file mode 100644 index 0000000..58852e6 --- /dev/null +++ b/algorithm-exercises-java/src/main/java/ae/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/RansomNote.java @@ -0,0 +1,63 @@ +package ae.hackerrank.interview_preparation_kit.dictionaries_and_hashmaps; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import util.Log; + +/** + * RansomNote. + * + * @link Problem definition [[docs/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/ctci-ransom-note.md]] + */ +public class RansomNote { + /** + * InvalidValueException. + */ + public class InvalidValueException extends Exception { + // constructor for the InvalidAgeException class + public InvalidValueException(String msg) { + Log.error(msg); + } + } + + protected RansomNote() { + } + + private static final String YES = "Yes"; + private static final String NO = "No"; + + /** + * checkMagazineCompute. + */ + public static boolean checkMagazineCompute(List magazine, List note) { + Map dictionary = new HashMap<>(); + + for (String word : magazine) { + if (dictionary.putIfAbsent(word, 1) != null) { + Integer currentValue = dictionary.get(word); + dictionary.put(word, currentValue + 1); + } + } + + for (String word : note) { + try { + dictionary.put(word, dictionary.get(word) - 1); + if (dictionary.get(word) < 0) { + throw new RansomNote().new InvalidValueException("Value can't go below 0"); + } + } catch (Exception e) { + return false; + } + } + + return true; + } + + /** + * checkMagazine. + */ + public static String checkMagazine(List magazine, List note) { + return checkMagazineCompute(magazine, note) ? YES : NO; + } +} diff --git a/algorithm-exercises-java/src/test/java/ae/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/RansomNoteTest.java b/algorithm-exercises-java/src/test/java/ae/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/RansomNoteTest.java new file mode 100644 index 0000000..dff49e4 --- /dev/null +++ b/algorithm-exercises-java/src/test/java/ae/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/RansomNoteTest.java @@ -0,0 +1,49 @@ +package ae.hackerrank.interview_preparation_kit.dictionaries_and_hashmaps; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import util.JsonLoader; + +@TestInstance(Lifecycle.PER_CLASS) +class RansomNoteTest { + + public static class RansomNoteTestCase { + public String title; + public List magazine; + public List note; + public String expected; + } + + List testCases; + + @BeforeAll + public void setup() throws IOException { + String path = String.join("/", "hackerrank", + "interview_preparation_kit", + "dictionaries_and_hashmaps", + "ctci_ransom_note.testcases.json"); + + this.testCases = JsonLoader.loadJson(path, RansomNoteTestCase.class); + } + + @Test void testArrayManipulation() { + for (RansomNoteTestCase test : testCases) { + String solutionFound = RansomNote.checkMagazine(test.magazine, test.note); + + assertEquals(test.expected, solutionFound, + String.format("%s(%s, %s) answer must be: %s", + "CrushOptimized.arrayManipulation", + test.magazine, + test.note, + test.expected + ) + ); + } + } +} diff --git a/algorithm-exercises-java/src/test/resources/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/ctci_ransom_note.testcases.json b/algorithm-exercises-java/src/test/resources/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/ctci_ransom_note.testcases.json new file mode 100644 index 0000000..8f04948 --- /dev/null +++ b/algorithm-exercises-java/src/test/resources/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/ctci_ransom_note.testcases.json @@ -0,0 +1,20 @@ +[ + { + "title": "Sample Test Case 0", + "magazine": ["give", "me", "one", "grand", "today", "night"], + "note": ["give", "one", "grand", "today"], + "expected": "Yes" + }, + { + "title": "Sample Test Case 1", + "magazine": ["two", "times", "three", "is", "not", "four"], + "note": ["two", "times", "two", "is", "four"], + "expected": "No" + }, + { + "title": "Sample Test", + "magazine": ["two", "two", "times", "three", "is", "not", "four"], + "note": ["two", "times", "two", "is", "four"], + "expected": "Yes" + } +] diff --git a/docs/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/ctci-ransom-note.md b/docs/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/ctci-ransom-note.md new file mode 100644 index 0000000..5ddf475 --- /dev/null +++ b/docs/hackerrank/interview_preparation_kit/dictionaries_and_hashmaps/ctci-ransom-note.md @@ -0,0 +1,102 @@ +# [Hash Tables: Ransom Notes](https://www.hackerrank.com/challenges/ctci-ransom-note) + +- Difficulty: `#easy` +- Category: `#ProblemSolvingIntermediate` `#dictionaries` `#hashmaps` + +Harold is a kidnapper who wrote a ransom note, but now he is worried it will be +traced back to him through his handwriting. He found a magazine and wants to +know if he can cut out whole words from it and use them to create an untraceable +replica of his ransom note. +The words in his note are case-sensitive and he must use only whole words +available in the magazine. +He cannot use substrings or concatenation to create the words he needs. + +Given the words in the magazine and the words in the ransom note, +print `Yes` if he can replicate his ransom note exactly using whole words +from the magazine; otherwise, print `No`. + +## Example + +`magazine` = "attack at dawn" `note` = "Attack at dawn" + +The magazine has all the right words, but there is a case mismatch. +The answer is `No`. + +## Function Description + +Complete the checkMagazine function in the editor below. +It must print `Yes` if the note can be formed using the magazine, or . + +checkMagazine has the following parameters: + +- `string magazine[m]`: the words in the magazine +- `string note[n]`: the words in the ransom note + +## Prints + +- string: either or , no return value is expected + +## Input Format + +The first line contains two space-separated integers, `m` and `n`, +the numbers of words in the and the , respectively. + +The second line contains `m` space-separated strings, each `magazine[i]`. + +The third line contains `n` space-separated strings, each `node[i]`. + +## Constraints + +- $ 1 \leq m, n \leq 30000 $ +- $ 1 \leq $ length of `magazine[i]` and `note[i]` $ \leq 5 $ +- Each word consists of English alphabetic letters (i.e., `a` to `z` and `A` to `Z`). + +## Sample Input 0 + +```text +6 4 +give me one grand today night +give one grand today +``` + +## Sample Output 0 + +```text +Yes +``` + +## Sample Input 1 + +```text +6 5 +two times three is not four +two times two is four +``` + +## Sample Output 1 + +```text +No +``` + +## Explanation 1 + +'two' only occurs once in the magazine. + +## Sample Input 2 + +```text +7 4 +ive got a lovely bunch of coconuts +ive got some coconuts +``` + +## Sample Output 2 + +```text +No +``` + +## Explanation 2 + +Harold's magazine is missing the word `some`.