Python Program to Convert Roman Numerals to Integer
roman_to_int = lambda s: sum(-v if i+1 where roman_map is a dictionary of Roman symbols to values. Examples
How to Think About It
Algorithm
Code
def roman_to_int(s): roman_map = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} result = 0 for i in range(len(s) - 1): if roman_map[s[i]] < roman_map[s[i + 1]]: result -= roman_map[s[i]] else: result += roman_map[s[i]] result += roman_map[s[-1]] return result print(roman_to_int('III')) print(roman_to_int('IX')) print(roman_to_int('MCMXCIV'))
Dry Run
Let's trace 'MCMXCIV' through the code
Initialize
result = 0, roman_map = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000}
Check M and C
M=1000, C=100; 1000 > 100 so add 1000; result=1000
Check C and M
C=100, M=1000; 100 < 1000 so subtract 100; result=900
Check M and X
M=1000, X=10; 1000 > 10 so add 1000; result=1900
Check X and C
X=10, C=100; 10 < 100 so subtract 10; result=1890
Check C and I
C=100, I=1; 100 > 1 so add 100; result=1990
Check I and V
I=1, V=5; 1 < 5 so subtract 1; result=1989
Add last symbol V
Add V=5; result=1994
| Index | Current Symbol | Next Symbol | Action | Result |
|---|---|---|---|---|
| 0 | M(1000) | C(100) | Add 1000 | 1000 |
| 1 | C(100) | M(1000) | Subtract 100 | 900 |
| 2 | M(1000) | X(10) | Add 1000 | 1900 |
| 3 | X(10) | C(100) | Subtract 10 | 1890 |
| 4 | C(100) | I(1) | Add 100 | 1990 |
| 5 | I(1) | V(5) | Subtract 1 | 1989 |
| 6 | V(5) | - | Add 5 | 1994 |
Why This Works
Step 1: Mapping Roman Symbols
Each Roman numeral symbol is linked to a fixed integer value using a dictionary for quick lookup.
Step 2: Comparing Adjacent Symbols
By comparing each symbol with the next, the code decides whether to add or subtract the current value.
Step 3: Handling Subtraction Cases
If a smaller value precedes a larger one, it subtracts the smaller to handle numerals like IV or IX correctly.
Step 4: Adding the Last Symbol
The last symbol's value is always added because it has no next symbol to compare.
Alternative Approaches
import re def roman_to_int_regex(s): roman_map = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} pattern = r'M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})' if not re.fullmatch(pattern, s): return 0 total = 0 i = 0 while i < len(s): if i+1 < len(s) and roman_map[s[i]] < roman_map[s[i+1]]: total += roman_map[s[i+1]] - roman_map[s[i]] i += 2 else: total += roman_map[s[i]] i += 1 return total print(roman_to_int_regex('MCMXCIV'))
def roman_to_int_stack(s): roman_map = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} stack = [] for char in s: while stack and roman_map[stack[-1]] < roman_map[char]: val = stack.pop() stack.append(char) stack.append(val) break else: stack.append(char) return sum(roman_map[c] for c in stack) print(roman_to_int_stack('IX'))
Complexity: O(n) time, O(1) space
Time Complexity
The program loops through the Roman numeral string once, so it runs in linear time relative to the input length.
Space Complexity
It uses a fixed dictionary and a few variables, so space usage is constant regardless of input size.
Which Approach is Fastest?
The direct comparison method is fastest and simplest; regex adds overhead, and stack-based methods are more complex.
| Approach | Time | Space | Best For |
|---|---|---|---|
| Direct Comparison | O(n) | O(1) | Simple and fast conversion |
| Regex Validation | O(n) with overhead | O(1) | Validating format before conversion |
| Stack Method | O(n) | O(n) | Demonstrating stack usage but less efficient |