Browse curriculum

Roman to Integer

Convert a Roman numeral to an integer in one pass with a symbol-value map: subtract a symbol that is smaller than the next one, otherwise add it.

Problem Understanding

Roman to Integer: convert a valid Roman numeral (1 to 3999) to an integer. Symbols are I 1, V 5, X 10, L 50, C 100, D 500, M 1000. They are written largest to smallest, except in six subtraction pairs: IV 4, IX 9, XL 40, XC 90, CD 400, CM 900.

Example: "MCMXCIV" returns 1994 (M = 1000, CM = 900, XC = 90, IV = 4).

The Intuition: Look One Symbol Ahead

Store the seven symbol values in a hash map (or a switch) for O(1) lookups. Then one rule handles every case:

  1. If the current symbol is smaller than the next one, it is the first half of a subtraction pair: subtract it.
  2. Otherwise add it.

IV is -1 + 5 = 4; VI is 5 + 1 = 6. There is no need to list the six pairs. Like Two Sum, the map turns each step into a constant-time lookup.

Interactive Walkthrough

Each symbol shows its value underneath. The current symbol is filled and the next one is marked, since that comparison decides the step. Subtracted symbols turn orange and added ones green. Try Every pair for a numeral built entirely from subtraction pairs.

Dry Run Table

Input: s = "MCMXCIV"

Symbol Value Next Action Total
M 1000 C (100) add 1000
C 100 M (1000) subtract 900
M 1000 X (10) add 1900
X 10 C (100) subtract 1890
C 100 I (1) add 1990
I 1 V (5) subtract 1989
V 5 — add 1994

Answer: 1994.

The Solution Template

A value map and a one-symbol look-ahead. C uses a switch instead of a map.

Roman to Integer Code
1var romanToInt = function(s) {
2 const value = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000 };
3 let total = 0;
4 for (let i = 0; i < s.length; i++) {
5 const v = value[s[i]];
6 if (i + 1 < s.length && v < value[s[i + 1]]) total -= v;
7 else total += v;
8 }
9 return total;
10};

Edge Cases & Common Mistakes

  • Last symbol: it has no next symbol, so it is always added; guard the look-ahead with i + 1 < n.
  • Equal neighbours (II, XX): equal is not smaller, so both are added.
  • Subtracting the pair twice: handle only the smaller symbol with the look-ahead; the larger one is then added normally.
  • Single symbol: "M" is 1000; the loop adds it.
  • Integer to Roman: the reverse problem, Integer to Roman (LeetCode 12), walks the same value table greedily from 1000 down to 1.

Summary

Map each symbol to its value. Walk the string once: subtract a symbol that is smaller than the one after it, add every other symbol. O(n) time and O(1) space.

More practice: DSA interview questions with answers · patterns cheat sheet

The approach, step by step

  1. Map symbols to values

    I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000.

  2. Compare with the next symbol

    For each symbol, if a next symbol exists and has a larger value, subtract the current value; otherwise add it.

  3. Return the total

    After the last symbol, the total is the integer.

Frequently asked questions

How do you handle subtraction pairs like IV and CM?

Roman numerals normally go from large to small. A smaller symbol directly before a larger one, as in IV or CM, means subtraction. So compare each symbol with the next: if it is smaller, subtract it; otherwise add it. IV becomes -1 + 5 = 4.


Why not match the six two-letter pairs explicitly?

You can (check IV, IX, XL, XC, CD, CM first and skip two characters), but the look-ahead rule covers all six with one comparison and no special cases.


Can you scan from right to left instead?

Yes. Keep the previous value; add the current value if it is at least the previous one, subtract it otherwise. It is the same rule seen from the other end.

Applying for software engineering roles? Free, no sign-up:

AI resume checker — match your resume to the job description