diff --git a/DIRECTORY.md b/DIRECTORY.md index 17951f0..27d5717 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -37,6 +37,8 @@ * [Mergesort](https://github.com/TheAlgorithms/Kotlin/blob/master/src/main/kotlin/sort/MergeSort.kt) * [Quicksort](https://github.com/TheAlgorithms/Kotlin/blob/master/src/main/kotlin/sort/QuickSort.kt) * [Selectionsort](https://github.com/TheAlgorithms/Kotlin/blob/master/src/main/kotlin/sort/SelectionSort.kt) + * String + * [Anagram](https://github.com/TheAlgorithms/Kotlin/blob/master/src/main/kotlin/string/Anagram.kt) * Test * Dynamic Programming * [Palindromepartitioningtest](https://github.com/TheAlgorithms/Kotlin/blob/master/src/test/kotlin/dynamic_programming/PalindromePartitioningTest.kt) @@ -72,3 +74,5 @@ * [Mergesorttest](https://github.com/TheAlgorithms/Kotlin/blob/master/src/test/kotlin/sort/MergeSortTest.kt) * [Quicksorttest](https://github.com/TheAlgorithms/Kotlin/blob/master/src/test/kotlin/sort/QuickSortTest.kt) * [Selectionsorttest](https://github.com/TheAlgorithms/Kotlin/blob/master/src/test/kotlin/sort/SelectionSortTest.kt) + * String + * [AnagramTest](https://github.com/TheAlgorithms/Kotlin/blob/master/src/test/kotlin/string/AnagramTest.kt) \ No newline at end of file diff --git a/src/main/kotlin/string/Anagram.kt b/src/main/kotlin/string/Anagram.kt new file mode 100644 index 0000000..17dbbc3 --- /dev/null +++ b/src/main/kotlin/string/Anagram.kt @@ -0,0 +1,48 @@ +package string + + +/** + * This method implements a simple anagram verifier algorithm + * + * @param string The string to be compared with + * @param ignoreWhitespace true if whitespaces should be ignored + * @param ignoreCase true if casing should be ignored + * + * Worst-case performance O(n) + * Best-case performance O(n) + * Average performance O(n) + * Worst-case space complexity O(N) + **/ +fun String.isAnagramOf(string: String, ignoreWhitespace: Boolean = true, ignoreCase: Boolean = true): Boolean { + val string1 = this.normalize(ignoreWhitespace, ignoreCase) + val string2 = string.normalize(ignoreWhitespace, ignoreCase) + + if (string1.length != string2.length) + return false + + val charMap1 = string1.toCharCountMap() + val charMap2 = string2.toCharCountMap() + + return charMap1 == charMap2 +} + +private fun String.toCharCountMap(): Map { + val charMap = mutableMapOf() + + this.forEach { + val count = charMap[it] ?: 0 + charMap[it] = count + 1 + } + + return charMap +} + +private fun Sequence.removeWhitespaces() = this.filter { it.isWhitespace().not() } + +private fun Sequence.toLowerCase() = this.map { it.toLowerCase() } + +private fun String.normalize(ignoreWhitespace: Boolean, ignoreCase: Boolean) = this + .asSequence() + .let { if (ignoreCase) it.toLowerCase() else it } + .let { if (ignoreWhitespace) it.removeWhitespaces() else it } + .joinToString("") diff --git a/src/test/kotlin/string/AnagramTest.kt b/src/test/kotlin/string/AnagramTest.kt new file mode 100644 index 0000000..caa5f4c --- /dev/null +++ b/src/test/kotlin/string/AnagramTest.kt @@ -0,0 +1,95 @@ +package string + +import org.junit.Test + + +class AnagramTest { + + @Test + fun `test isAnagramOf empty string returns true`() { + val string1 = "" + val string2 = "" + + assert(string1.isAnagramOf(string2)) + } + + @Test + fun `test isAnagramOf single letter string returns true`() { + val string1 = "a" + val string2 = "a" + + assert(string1.isAnagramOf(string2)) + } + + @Test + fun `test isAnagramOf returns true`() { + val string1 = "testIsAnagramOfReturnsTrue1" + val string2 = "test isAnagramOf returns true 1" + + assert(string1.isAnagramOf(string2)) + } + + @Test + fun `test isAnagramOf ignoreWhitespace true ignoreCase True returns True`() { + val string1 = "Wolfgang Amadeus Mozart" + val string2 = "A famous german waltz god" + + assert(string1.isAnagramOf(string2, ignoreWhitespace = true, ignoreCase = true)) + } + + @Test + fun `test isAnagramOf ignoreWhitespace False ignoreCase True returns True`() { + val string1 = "Eleven plus Two" + val string2 = "Twelve plus One" + + assert(string1.isAnagramOf(string2, ignoreWhitespace = false, ignoreCase = true)) + } + + @Test + fun `test isAnagramOf ignoreWhitespace True ignoreCase False returns True`() { + val string1 = "wolfgang amadeus mozart" + val string2 = "a famous german waltz god" + + assert(string1.isAnagramOf(string2, ignoreWhitespace = true, ignoreCase = false)) + } + + @Test + fun `test isAnagramOf ignoreWhitespace False ignoreCase False returns True`() { + val string1 = "wolfgangamadeusmozart" + val string2 = "afamousgermanwaltzgod" + + assert(string1.isAnagramOf(string2, ignoreWhitespace = false, ignoreCase = false)) + } + + @Test + fun `test isAnagramOf ignoreWhitespace true ignoreCase True returns False`() { + val string1 = "testIsAnagramOfReturnsTrue1" + val string2 = "test isAnagramOf returns true 2" + + assert(string1.isAnagramOf(string2, ignoreWhitespace = true, ignoreCase = true).not()) + } + + @Test + fun `test isAnagramOf ignoreWhitespace False ignoreCase True returns False`() { + val string1 = "testIsAnagramOfReturnsTrue1" + val string2 = "test IsAnagramOf Returns True 1" + + assert(string1.isAnagramOf(string2, ignoreWhitespace = false, ignoreCase = true).not()) + } + + @Test + fun `test isAnagramOf ignoreWhitespace True ignoreCase False returns False`() { + val string1 = "testIsAnagramOfReturnsTrue1" + val string2 = "testisAnagramOfreturnstrue1" + + assert(string1.isAnagramOf(string2, ignoreWhitespace = true, ignoreCase = false).not()) + } + + @Test + fun `test isAnagramOf ignoreWhitespace False ignoreCase False returns False`() { + val string1 = "testisanagramofreturnstrue" + val string2 = "testisanagramofreturnstrup" + + assert(string1.isAnagramOf(string2, ignoreWhitespace = false, ignoreCase = false).not()) + } +} \ No newline at end of file