EasyArrays & Hashing

Roman to Integer โ€” Solution

Problem

Given a Roman numeral string, return its integer value. Roman numerals use seven symbols (I=1, V=5, X=10, L=50, C=100, D=500, M=1000), with one twist: when a smaller value appears immediately before a larger one, it's subtracted rather than added โ€” so IV=4 and CM=900.

  • Input: s = "MCMXCIV"

  • Output: 1994

  • Explanation: M(1000) + CM(900) + XC(90) + IV(4) = 1994

  • Input: s = "LVIII"

  • Output: 58

  • Explanation: L(50) + V(5) + I(1) + I(1) + I(1) = 58

Intuition

The subtraction rule only ever applies when a smaller symbol immediately precedes a larger one. So one left-to-right pass is enough: look one step ahead at each position, and if the current symbol is worth less than the next one, subtract it instead of adding it. No special-casing needed for IV, IX, XL, etc. โ€” the comparison handles all six subtraction pairs automatically.

Solution โ€” Left-to-Right Comparison

Scan the string once, comparing each character's value to the next character's value to decide whether to add or subtract.

  1. Build a lookup map of the 7 Roman symbols to their integer values.
  2. Iterate through the string from left to right.
  3. At each position, look up the current symbol's value and (if it exists) the next symbol's value.
  4. If the current value is less than the next value, subtract the current value from the total (it's part of a subtraction pair).
  5. Otherwise, add the current value to the total.
  6. Return the total.
1def romanToInt(s: str) -> int:
2    roman_values = {'I': 1, 'V': 5, 'X': 10, 'L': 50,
3                    'C': 100, 'D': 500, 'M': 1000}
4    total = 0
5    for i in range(len(s)):
6        current_value = roman_values[s[i]]
7        next_value = roman_values[s[i + 1]] if i + 1 < len(s) else 0
8        # subtract when a smaller symbol comes before a larger one
9        if current_value < next_value:
10            total -= current_value
11        else:
12            total += current_value
13    return total

Time: O(n) โ€” single pass through the string of length n.

Space: O(1) โ€” the symbol map has exactly 7 entries regardless of input size.

Complexity Summary

ApproachTimeSpaceWhen to use
Left-to-Right ComparisonO(n)O(1)Always โ€” this is the canonical solution

Common Mistakes

  • Hardcoding all six subtraction pairs explicitly (checking s[i:i+2] == "IV", etc.) instead of using the general comparison rule โ€” it works but produces six times as much code and misses the elegant insight.
  • Checking s[i] < s[i+1] without guarding against the last index โ€” the final character has no successor, so you must either guard with a bounds check or default the "next value" to 0.
  • Scanning right to left without adjusting the comparison direction โ€” a right-to-left scan also works (track the previous value and subtract if current is smaller), but mixing up the direction of the comparison flips all the add/subtract decisions.
  • Forgetting that the same symbol can appear in both additive and subtractive roles โ€” I is added in "III" but subtracted in "IX"; only the relative order with the next character determines which.
  • Using string replacement (e.g., replacing "IV" with "IIII" before summing) โ€” technically correct but obscures the pattern and is error-prone for longer subtraction sequences.

Related Problems

  • integer-to-roman โ€” the exact inverse: build a Roman numeral from an integer using the same symbol table
  • add-binary โ€” another problem where you process a string representation of a number one character at a time
  • multiply-strings โ€” digit-by-digit string arithmetic using a similar positional scanning pattern
  • valid-palindrome โ€” left-to-right string scanning with character-level decisions
  • reverse-integer โ€” integer manipulation where overflow and digit extraction are the key challenges

Ready to practice? Try it on SkillFlow

Adaptive problems, AI follow-up interviews, and a skill score that shows exactly where you need to improve.

Practice This Problem โ†’