[LeetCode]RomanToInteger
By: Trevor Low
Tags: Leetcode, Algorithms, JavaScript

The Problem

https://leetcode.com/problems/roman-to-integer/

Roman numerals are represented by seven different symbols: I , V , X , L , C , D and M .

For example, 2 is written as II in Roman numeral, just two one's added together. 12 is written as XII , which is simply X + II . The number 27 is written as XXVII , which is XX + V + II .

Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII . Instead, the number four is written as IV . Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX . There are six instances where subtraction is used:

I can be placed before V (5) and X (10) to make 4 and 9.

can be placed before (5) and (10) to make 4 and 9. X can be placed before L (50) and C (100) to make 40 and 90.

can be placed before (50) and (100) to make 40 and 90. C can be placed before D (500) and M (1000) to make 400 and 900.

Given a roman numeral, convert it to an integer.

First Instinct

My first instinct was to create a hash dictionary to store each of the original and stand alone roman numerals with their values like so.

const dict = { I:1, V:5, X:10, L:50, C:100, D:500, M:1000 }

I like to break apart the algorithm into digestible pieces, so I ignored the edge cases of IX, IV, etc, and just focused on a way to add up the characters in the string.

It came to me pretty quickly, use a loop to find the value of each character in the string and add to a total, then return the total. Mine looked like this…

function romanToInt(str){ let total = 0; for(let i = 0; i<str.length; i++){ let char = str[i]; total += dict[char]; } return total }

Now, I wanted to consider the edge cases. At first I thought I would have to create a ton of if else statements and use multiple pointers to find the next value to compare to. However, I knew there must be an easier and more efficient way of doing this because whenever code seems too tedious, it usually is. I went back to the prompt and read it carefully. The piece of information that stood out to me was ‘Roman numerals are usually written largest to smallest from left to right.’ Hmmm, so when they are not, we have a value that is less than the two numerals. For IV, with our code above it would read as 6, but with the edge case in place it would be 4, or V -I. And it works for the rest too! Try some out, I did when I was initially pseudo coding it out and all edge cases work!

Solution

So how do we implement this in code? Well, first we have to store the next char after out initial in a value. We need an if statement that says if char value is less than next value, we subtract the current char’s value we are on and move on. Else we add the current char’s value. So with something like IV, we would subtract 1 from the total for the I, move onto V, see there is nothing after V and then add 5 to the total resulting in total = 4.

function romanToInt(str){ let total = 0; for(let i = 0; i<str.length; i++){ let char = str[i]; let next = str[i+1]; if(dict[char]<dict[next]){ total -= dict[char] }else{ total += dict[char]; } } return total }

Big O

The time complexity if O(n) because we have to loop through the entire string.

The space complexity is O(1) because although we have to store values in a hash, it is constant no matter the length of the string.