Daily LeetCode Challenges.

Daily LeetCode Challenges.

Convert Roman Numerals To Their Integer Value

Hey,

I decided to start taking blogging a little more seriously. While lost in thought, I came up with an idea. I decided that since I already push my LeetCode problems to my GitHub, I might as well reflect on them as well. I will use this opportunity to talk about what I learned from the challenge, where I got stuck, my approach, and so on. I will attempt to commit to a couple of articles a week to avoid burnout. But as I figure out my groove, I will attempt to increase the frequency of articles.

Convert Roman Numerals To Their Integer Value.

Today's LeetCode Challenge was the convert the Roman Numerals to their integer value equivalent. You can find the problem on LeetCode here. It is labeled easy.

My first reaction was that I froze. I immediately realized I don't really know my Roman Numerals. The problem wanted us to solve for integers up to 3999. And I was unfamiliar with the mechanics of Roman Numerals and when all the letters come in. Luckily for me, the problem had me covered.

In the problem, there was a table provided to give you the conversion from Roman Numerals to integers.

Symbol       Value
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

However, based on the placement of the symbols, the value changes. So, their order matters. The value changes are as follows:

  • If I is placed before V the value is 4
  • If I is placed before X the value is 9
  • If X is placed before L the value is 40
  • If X is placed before C the value is 90
  • If C is placed before D the value is 400
  • If C is placed before M the value is 900

The approach

The way I decided to tackle this problem was by first finding out all the parameters I was getting passed. In this particular problem, I only had to worry about strings. No funny business such as arrays or integers.

I next needed to determine what was being asked to be returned. In this problem, we only needed to return the integer value of the Roman Numerals.

Once, I figured those two parts out, I started building my function. I used the examples from the problem, so I did not feel the need to build any additional test cases.

Now that I had my parameters and returns figured out, I needed to figure out my function. I sat there for a moment determining how I would tackle a problem like this. I decided the easiest way for me to attempt this is to convert a string into an array using the split method. I would then iterate through the array looking at each element and determining its value and then added it to a sum variable. The solution worked for numbers up to the number 3.

Looking at individual elements did not take into account the changes in values based on the neighboring elements. So I needed to take into account the changes in values by comparing the element to the next element using conditionals, changing the value being added to the sum variable. This solution worked, but there was an edge case that I was still missing.

Because I needed to figure out how to deal with pair Roman Numerals, for example, IV, I needed to be aware that I didn't double count an element. So I added a final conditional to determine that if none of the other conditionals were triggered, to add 0 to the sum, which meant that the solution didn't change.

I initially brute-forced the solution with a for-loop and refactored the code with the reduce method.

If you want to view my solutions, I will post them at the end of the article. I will showcase both my brute force and the refactored solutions. They are not perfect. When I ran them against other solutions, they ran in about 250ms. They have about the same runtime.

Lessons learned

This problem really taught me how to use the reduce method outside of the standard method.

arr.reduce( (previousValue, currentValue) => previousValue + currentValue, 0 )

The for-loop did not give me too much trouble, and as soon as I figured out the edge cases and the bugs in my code, the problem solved itself quite easily. But with the reduce method, I kept running into undefined returns. I began scouring the internet looking for solutions to the problem I was having with the method. As well as reaching out to a few developer friends.

My developer friends came back to me and informed me that I was missing my return in the reduce method. This was the first time I had introduced conditionals into a reduce method, and I was not aware before this that I needed to place a return inside the method.

Once I did that, my code broke. I started getting things returned but at certain points, the reduce method would start returning characters instead of integers. This had me perplexed for a while. I could not understand why this was happening. I started tinkering around with my equations thinking something was wrong there. Started changing what would happen in each conditional alternating between currentValue and previousValue += and regular equations. I tried it all.

It turns out one of my conditionals had a bug in them and because it was never triggering, it kept adding the element instead of converting it to its representative value.

I also learned another thing about returns today. You need to store your reduce method into a variable and return that variable. You cannot just return the reduce method.

Thank you for reading! I hope you learned something.

Solution

Here is my brute-force solution:

var romanToInt = function(s) {
    // declare a variable to hold the total
    let sum = 0
    // take string and separate the elements
    let newS = s.split('')
    // go through each element and replace it with a value
    for (let i = 0; i <newS.length; i++) {
        if (newS[i] === "C" && newS[i+1] === "M") { sum += 900}
        else if (newS[i] === "C" && newS[i+1] === "D") {sum += 400}
        else if (newS[i] === "X" && newS[i+1] === "C") {sum += 90}
        else if (newS[i] === "X" && newS[i+1] === "L") {sum += 40}
        else if (newS[i] === "I" && newS[i+1] === "X") {sum += 9}
        else if (newS[i] === "I" && newS[i+1] === "V") {sum += 4}
        else if (newS[i] === "M" && newS[i-1] !== "C") {sum += 1000}
        else if (newS[i] === "D" && newS[i-1] !== "C") {sum += 500}
        else if (newS[i] === "C" && newS[i-1] !== "X") {sum += 100}
        else if (newS[i] === "L" && newS[i-1] !== "X") {sum += 50}
        else if (newS[i] === "X" && newS[i-1] !== "I") {sum += 10}
        else if (newS[i] === "V" && newS[i-1] !== "I") {sum += 5}
        else if (newS[i] === "I") {sum++}
        // console.log(i)
        // console.log(sum)
    }
    // return the sum of all values 
    return sum

};

Here is my refactored solution:

var romanToInt = function(s) {
    let newS = s.split('')

    let result = newS.reduce( (pv, cv, i, newS ) => {
        if (newS[i] === "C" && newS[i+1] === "M") { cv = pv + 900}
        else if (newS[i] === "C" && newS[i+1] === "D") {cv = pv + 400}
        else if (newS[i] === "X" && newS[i+1] === "C") {cv = pv + 90}
        else if (newS[i] === "X" && newS[i+1] === "L") {cv = pv + 40}
        else if (newS[i] === "I" && newS[i+1] === "X") {cv = pv + 9}
        else if (newS[i] === "I" && newS[i+1] === "V") {cv = pv + 4}
        else if (newS[i] === "M" && newS[i-1] !== "C") {cv = pv + 1000}
        else if (newS[i] === "D" && newS[i-1] !== "C") {cv = pv + 500}
        else if (newS[i] === "C" && newS[i-1] !== "X") {cv = pv + 100}
        else if (newS[i] === "L" && newS[i-1] !== "X") {cv = pv + 50}
        else if (newS[i] === "X" && newS[i-1] !== "I") {cv = pv + 10}
        else if (newS[i] === "V" && newS[i-1] !== "I") {cv = pv + 5}
        else if (newS[i] === "I") {cv = pv + 1}
        else {cv = pv + 0}
        return cv} , 0 )

    return result
};

Afternote

One thing I thought about after writing out this article and console logging the index value in my brute-force solution. Maybe if I find a pair and I would like to reduce the runtime of my solution, I can add an i++ to my altered values after my equation and skip the next index.

Did you find this article valuable?

Support Jamil Sinno by becoming a sponsor. Any amount is appreciated!