I have solved the Ransom Note challenge on HackerRank using JavaScript / ECMAScript 6. The challenge goes like this:
A kidnapper wrote a ransom note but is worried it will be traced back to him. 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 whole words available in the magazine, meaning 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, printNo
.Input Format
The first line contains two space-separated integers describing the respective values of (the number of words in the magazine) and (the number of words in the ransom note).
The second line contains space-separated strings denoting the words present in the magazine.
The third line contains space-separated strings denoting the words present in the ransom note.
My solution uses JavaScript Map
objects (as suggested by the name of the challenge) and passes all tests with no timeouts. However, the solution itself is very literal, as in, it removes out each word in the ransom note from the magazine, unless the needed word is not available.
Note that the portion of code above ignore above this line
is included with all challenges on the site, I left it in for the sake of completeness, so that anyone can copy-paste the whole block into the challenge page, if they wish.
process.stdin.resume();
process.stdin.setEncoding('ascii');
var input_stdin = "";
var input_stdin_array = "";
var input_currentline = 0;
process.stdin.on('data', function (data) {
input_stdin += data;
});
process.stdin.on('end', function () {
input_stdin_array = input_stdin.split("\n");
main();
});
function readLine() {
return input_stdin_array[input_currentline++];
}
/////////////// ignore above this line ////////////////////
const addValueOrIncrementCount = (value, map) => {
let count = map.get(value)
if (count) {
map.set(value, ++count)
} else {
map.set(value, 1)
}
return count
}
const decrementCountIfPossible = (value, map) => {
let count = map.get(value)
if (!count) {
return null
} else {
map.set(value, --count)
return count
}
}
const mapWordCounts = inputString => {
const output = new Map()
let occurrences
for (let word of inputString.split(" ")) {
addValueOrIncrementCount(word, output)
}
return output
}
const isRansomComposedFromMagazine = (ransom, magazine) => {
const ransomMap = mapWordCounts(ransom)
const magazineMap = mapWordCounts(magazine)
let ransomWordFromMagazine
for (let [word, count] of ransomMap.entries()) {
while (count > 0) {
ransomWordFromMagazine = decrementCountIfPossible(word, magazineMap)
if (ransomWordFromMagazine === null) {
return false
}
count--
}
}
return true
}
const getProgramInput = () => {
const firstLine = readLine().split(' ')
const magazineWordCount = parseInt(firstLine[0])
const ransomWordCount = parseInt(firstLine[1])
const magazine = readLine()
const ransom = readLine()
return {
magazineWordCount: magazineWordCount,
ransomWordCount: ransomWordCount,
magazine: magazine,
ransom: ransom
}
}
const main = () => {
const input = getProgramInput()
console.log(isRansomComposedFromMagazine(input.ransom, input.magazine) ? "Yes" : "No")
}
while (count > 0)
loop seems unnecessary. Why not just add acount
parameter todecrementIfPossible
? I notice that you don't use semi-colons at all. Although not a requirement I would recommend that you do - there are enough cases where this will cause you problems. \$\endgroup\$