diff --git a/docs/hackerrank/interview_preparation_kit/string_manipulation/sherlock-and-valid-string.md b/docs/hackerrank/interview_preparation_kit/string_manipulation/sherlock-and-valid-string.md new file mode 100644 index 00000000..556bf1d4 --- /dev/null +++ b/docs/hackerrank/interview_preparation_kit/string_manipulation/sherlock-and-valid-string.md @@ -0,0 +1,109 @@ +# [String Manipulation: Sherlock and the Valid String](https://www.hackerrank.com/challenges/sherlock-and-valid-string) + +- Difficulty: `#medium` +- Category: `#ProblemSolvinIntermediate` `#strings` + +Sherlock considers a string to be valid if all characters of the string appear +the same number of times. +It is also valid if he can remove just ´1´ character at index in the string, +and the remaining characters will occur the same number of times. +Given a string `s`, determine if it is valid. +If so, return `YES`, otherwise return `NO`. + +## Example + +`s = abc` + +This is a valid string because frequencies are `{a: 1, b: 1, c: 1}`. + +`s = abcc` + +This is a valid string because we can remove one `c` and have of +each character in the remaining string. + +`s = abccc` + +This string is not valid as we can only remove `1` occurrence of `c`. +That leaves character frequencies of `{a: 1, b: 1, c: 2}`. + +## Function Description + +Complete the isValid function in the editor below. + +isValid has the following parameter(s): + +- `string s`: a string + +## Returns + +- `string`: either `YES` or `NO` + +## Input Format + +A single string `s`. + +## Constraints + +- $ 1 \leq |s| \leq 10^5 $ +- Each character `s[i]` $ \in $ `ascii[a-z]` + +## Sample Input 0 + +```text +aabbcd +``` + +## Sample Output 0 + +```text +NO +``` + +## Explanation 0 + +Given `s = "abbcd"`, we would need to remove two characters, +both `c` and `d` -> `aabb` or a and b abcd, to make it valid. +We are limited to removing only one character, so `s` is invalid. + +## Sample Input 1 + +```text +aabbccddeefghi +``` + +## Sample Output 1 + +```text +NO +``` + +## Explanation 1 + +Frequency counts for the letters are as follows: + +```text +{'a': 2, 'b': 2, 'c': 2, 'd': 2, 'e': 2, 'f': 1, 'g': 1, 'h': 1, 'i': 1} +``` + +There are two ways to make the valid string: + +- Remove `4` characters with a frequency of `1`: `{fghi}`. +- Remove `5` characters of frequency `2`: `{abcde}`. +Neither of these is an option. + +## Sample Input 2 + +```text +abcdefghhgfedecba +``` + +## Sample Output 2 + +```text +YES +``` + +## Explanation 2 + +All characters occur twice except for `e` which occurs `3` times. +We can delete one instance of `e` to have a valid string. diff --git a/src/hackerrank/interview_preparation_kit/string_manipulation/sherlock_and_valid_string.test.ts b/src/hackerrank/interview_preparation_kit/string_manipulation/sherlock_and_valid_string.test.ts new file mode 100644 index 00000000..a31b0296 --- /dev/null +++ b/src/hackerrank/interview_preparation_kit/string_manipulation/sherlock_and_valid_string.test.ts @@ -0,0 +1,18 @@ +import { describe, expect, it } from '@jest/globals'; + +import { isValid } from './sherlock_and_valid_string'; +import TEST_CASES from './sherlock_and_valid_string.testcases.json'; + +describe('isValid', () => { + it('isValid test cases', () => { + expect.assertions(9); + + const __YES__ = 'YES'; + + TEST_CASES.forEach((test) => { + const result = isValid(test.input) === __YES__; + + expect(result).toStrictEqual(test.expected); + }); + }); +}); diff --git a/src/hackerrank/interview_preparation_kit/string_manipulation/sherlock_and_valid_string.testcases.json b/src/hackerrank/interview_preparation_kit/string_manipulation/sherlock_and_valid_string.testcases.json new file mode 100644 index 00000000..b4194b17 --- /dev/null +++ b/src/hackerrank/interview_preparation_kit/string_manipulation/sherlock_and_valid_string.testcases.json @@ -0,0 +1,47 @@ +[ + { + "title": "counterexample", + "input": "aabbccc", + "expected": true + }, + { + "title": "counterexample", + "input": "a", + "expected": true + }, + { + "title": "counterexample", + "input": "aaa", + "expected": true + }, + { + "title": "counterexample", + "input": "abbccc", + "expected": false + }, + { + "title": "counterexample", + "input": "bbccc", + "expected": false + }, + { + "title": "Sample Test case 0", + "input": "aabbcd", + "expected": false + }, + { + "title": "Sample Test case 1", + "input": "aabbccddeefghi", + "expected": false + }, + { + "title": "Sample Test case 2", + "input": "abcdefghhgfedecba", + "expected": true + }, + { + "title": "Sample Test case 4", + "input": "aabbc", + "expected": true + } +] diff --git a/src/hackerrank/interview_preparation_kit/string_manipulation/sherlock_and_valid_string.ts b/src/hackerrank/interview_preparation_kit/string_manipulation/sherlock_and_valid_string.ts new file mode 100644 index 00000000..010280c0 --- /dev/null +++ b/src/hackerrank/interview_preparation_kit/string_manipulation/sherlock_and_valid_string.ts @@ -0,0 +1,55 @@ +/** + * @link Problem definition [[docs/hackerrank/interview_preparation_kit/string_manipulation/sherlock-and-valid-string.md]] + */ + +const __YES__ = 'YES'; +const __NO__ = 'NO'; + +export function isValidCompute(s: string): boolean { + if (s.length <= 1) { + return true; + } + + const stringMap: Record = {}; + + for (const letter of s.split('')) { + stringMap[letter] = stringMap?.[letter] ? stringMap[letter] + 1 : 1; + } + + const frequencies: Record = {}; + + for (const event of Object.values(stringMap)) { + frequencies[event] = frequencies?.[event] ? frequencies[event] + 1 : 1; + } + + const frequenciesSize = Object.entries(frequencies).length; + + if (frequenciesSize === 1) { + return true; + } + + if (frequenciesSize === 2) { + const frequenciesList = Object.entries(frequencies).sort( + ([, a], [, b]) => a - b + ); + const __RADIX__ = 10; + const __TOLERANCE__ = 1; + const minorFreq: number = parseInt(frequenciesList[0][0], __RADIX__); + const majorFreq: number = parseInt(frequenciesList[1][0], __RADIX__); + + if ( + frequencies[minorFreq] === __TOLERANCE__ && + (minorFreq === __TOLERANCE__ || minorFreq - majorFreq === __TOLERANCE__) + ) { + return true; + } + } + + return false; +} + +export function isValid(s: string): string { + return isValidCompute(s) ? __YES__ : __NO__; +} + +export default { isValid };