diff --git a/problems/roman-to-integer.kt b/problems/roman-to-integer.kt new file mode 100644 index 0000000..1c68415 --- /dev/null +++ b/problems/roman-to-integer.kt @@ -0,0 +1,62 @@ +class Solution { + /** + * Holds fixed mapping of roman numerals to their respective numeric value. + */ + private val values = mapOf( + 'I' to 1, 'V' to 5, 'X' to 10, 'L' to 50, 'C' to 100, 'D' to 500, 'M' to 1000 + ) + + /** + * Represents an accumulator for right fold when turning roman numeral into an integer value. + * @property sum Holds the current sum of the accumulator. + * @property next Holds the value of the previous roman numeral digit. + */ + private data class Accumulator(val sum: Int = 0, val next: Int = 0) { + /** + * @param it Current roman numeral digit. + * @return Sign that is to be used when modifying sum of the accumulator. + */ + private fun sign(it: Int): Int = when (next > it) { + true -> -1 + false -> 1 + } + + /** + * @param it Currently processed roman numeral digit. + * @return Correctly updated accumulator. + */ + fun update(it: Int): Accumulator = copy(sum = sum + sign(it) * it, next = it) + } + + fun romanToInt(s: String): Int = s + .map { values[it]!! } + .foldRight(Accumulator()) { it, acc -> + acc.update(it) + } + .sum +} + +fun main() { + val s = Solution() + + val tests = mapOf( + "I" to 1, + "II" to 2, + "III" to 3, + "IV" to 4, + "V" to 5, + "VI" to 6, + "VII" to 7, + "VIII" to 8, + "IX" to 9, + "X" to 10, + "LVIII" to 58, + "MCMXCIV" to 1994 + ) + + tests.forEach { (num, i) -> + check(s.romanToInt(num) == i) { + "$num: ${s.romanToInt(num)} == $i" + } + } +}