Roman to Integer solution and explanation
9 more videos on this problem
Roman to Integer - Leetcode 13 - PythonNeetCode · 7:57 · 236K views
Roman to Integer | Leetcode -13 | Algorithms Made EasyAlgorithms Made Easy · 5:22 · 172K views
LeetCode 13: Roman To IntegerAbstracted Away · 9:14 · 41K views
Roman to Integer - Leetcode 13 - Arrays & Strings (Python)Greg Hogg · 6:15 · 40K views
Roman to Integer | Leetcode 13 | Top 150 interview question seriesTechnosage · 13:41 · 38K views
LeetCode 13 | ROMAN TO INTEGER | C++ [ Approach and Code Explanation]Krishna Teaches · 8:59 · 33K views
Roman To Integer | Leetcode 13Techdose · 10:21 · 17K views
LeetCode Tutorial 13. Roman to IntegerGoodTecher · 13:38 · 16K views
13. Roman to Integer | Day 005 | Short & Simple SolutionAryan Mittal · 5:15 · 16K views
Roman to Integer - LeetCode 13 | JavaCode with Carter · 6:22 · 13K views
The problem
Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.
Symbol Value I 1 V 5 X 10 L 50 C 100 D 500 M 1000
For example, 2 is written as II in Roman numeral, just two ones 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:
Ican be placed beforeV(5) andX(10) to make 4 and 9.Xcan be placed beforeL(50) andC(100) to make 40 and 90.Ccan be placed beforeD(500) andM(1000) to make 400 and 900.
Given a roman numeral, convert it to an integer.
Example 1:
Input: s = "III" Output: 3 Explanation: III = 3.
Example 2:
Input: s = "LVIII" Output: 58 Explanation: L = 50, V= 5, III = 3.
Example 3:
Input: s = "MCMXCIV" Output: 1994 Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.
Constraints:
1 <= s.length <= 15scontains only the characters('I', 'V', 'X', 'L', 'C', 'D', 'M').- It is guaranteed that
sis a valid roman numeral in the range[1, 3999].
Approach overview
Problem Overview: Roman numerals represent numbers using characters like I, V, X, L, C, D, and M. Each symbol has a value, but smaller symbols placed before larger ones indicate subtraction (e.g., IV = 4). The task is to convert a Roman numeral string into its integer value while correctly handling these subtractive patterns.
Approach 1: Linear Scan from Left to Right (O(n) time, O(1) space)
Store the value of each Roman symbol in a small lookup structure such as a hash table. Iterate through the string from left to right. For each character, compare its value with the value of the next character. If the current value is smaller than the next one, subtract it from the total because this represents a subtractive pair (for example, I before V). Otherwise, add the value normally. This approach directly models how Roman numerals are written and keeps the logic simple. The iteration touches each character once, giving O(n) time complexity, while the lookup map and a few variables keep space at O(1).
This method is intuitive and mirrors the rules of Roman numerals closely. Many candidates start with this approach because it clearly expresses the subtractive rule and is easy to debug during interviews.
Approach 2: Optimized Reverse Iteration (O(n) time, O(1) space)
Instead of checking the next symbol, iterate from right to left. Maintain the value of the previous numeral seen during the traversal. For each symbol, look up its value from the same mapping structure (again typically implemented with a hash table). If the current value is smaller than the previous value, subtract it from the total. Otherwise, add it and update the previous value.
The key insight is that Roman numerals only subtract when a smaller symbol appears before a larger one. When scanning from the end, the "previous" value naturally represents the larger numeral in those cases. This eliminates the need to check the next character or manage index bounds. The algorithm still performs a single pass over the string, so the time complexity remains O(n) and space stays O(1). Many engineers prefer this version because the subtraction rule becomes a simple comparison with the last processed value.
Recommended for interviews: Both approaches are linear and acceptable. Interviewers typically expect the reverse-iteration solution because the logic is cleaner and avoids look‑ahead checks. Starting with the left‑to‑right scan demonstrates that you understand Roman numeral subtraction rules, then refining it to the reverse traversal shows strong algorithmic thinking. The core idea in both implementations is constant-time value lookup combined with a single pass over the input using basic math comparisons.
Approach 1: Linear Scan from Left to Right
The key idea is to traverse the given Roman numeral string from left to right. As we process each character, we compare it with the next one. If the current character has a smaller value than the next one, it means we are in a subtraction scenario (like IV = 4), so we subtract the value of the current character. Otherwise, we add its value.
def romanToInt(s: str) -> int:
values = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
total = 0
for i in range(len(s)):
if i + 1 < len(s) and values[s[i]] < values[s[i + 1]]:
total -= values[s[i]]
else:
total += values[s[i]]
return total
print(romanToInt('MCMXCIV')) # Output: 1994import java.util.HashMap;
import java.util.Map;
public class RomanToInt {
public int romanToInt(String s) {
Map<Character, Integer> values = new HashMap<>();
values.put('I', 1);
values.put('V', 5);
values.put('X', 10);
values.put('L', 50);
values.put('C', 100);
values.put('D', 500);
values.put('M', 1000);
int total = 0;
for (int i = 0; i < s.length(); i++) {
if (i + 1 < s.length() && values.get(s.charAt(i)) < values.get(s.charAt(i + 1))) {
total -= values.get(s.charAt(i));
} else {
total += values.get(s.charAt(i));
}
}
return total;
}
public static void main(String[] args) {
RomanToInt converter = new RomanToInt();
System.out.println(converter.romanToInt("MCMXCIV")); // Output: 1994
}
}#include <iostream>
#include <unordered_map>
int romanToInt(const std::string& s) {
std::unordered_map<char, int> values = {{'I', 1}, {'V', 5}, {'X', 10}, {'L', 50},
{'C', 100}, {'D', 500}, {'M', 1000}};
int total = 0;
for (size_t i = 0; i < s.length(); ++i) {
if (i + 1 < s.length() && values[s[i]] < values[s[i + 1]]) {
total -= values[s[i]];
} else {
total += values[s[i]];
}
}
return total;
}
int main() {
std::string roman = "LVIII";
std::cout << romanToInt(roman) << std::endl; // Output: 58
return 0;
}function romanToInt(s) {
const values = {
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000
};
let total = 0;
for (let i = 0; i < s.length; i++) {
if (i + 1 < s.length && values[s[i]] < values[s[i + 1]]) {
total -= values[s[i]];
} else {
total += values[s[i]];
}
}
return total;
}
console.log(romanToInt('MCMXCIV')); // Output: 1994#include <stdio.h>
#include <string.h>
int romanToInt(char* s) {
int values[256] = {};
values['I'] = 1;
values['V'] = 5;
values['X'] = 10;
values['L'] = 50;
values['C'] = 100;
values['D'] = 500;
values['M'] = 1000;
int total = 0;
int length = strlen(s);
for (int i = 0; i < length; i++) {
if (i + 1 < length && values[s[i]] < values[s[i + 1]]) {
total -= values[s[i]];
} else {
total += values[s[i]];
}
}
return total;
}
int main() {
char roman[] = "MCMXCIV";
printf("%d\n", romanToInt(roman)); // Output: 1994
return 0;
}using System;
using System.Collections.Generic;
class RomanToInt {
public int RomanToIntFunc(string s) {
Dictionary<char, int> values = new Dictionary<char, int> {
{'I', 1}, {'V', 5}, {'X', 10}, {'L', 50},
{'C', 100}, {'D', 500}, {'M', 1000}
};
int total = 0;
for (int i = 0; i < s.Length; i++) {
if (i + 1 < s.Length && values[s[i]] < values[s[i + 1]]) {
total -= values[s[i]];
} else {
total += values[s[i]];
}
}
return total;
}
static void Main(string[] args) {
RomanToInt converter = new RomanToInt();
Console.WriteLine(converter.RomanToIntFunc("LVIII")); // Output: 58
}
}The Python solution uses a dictionary to map Roman characters to integers. It scans the string, adding or subtracting values based on the adjacency conditions.
Time Complexity: O(n).
Space Complexity: O(1).
Approach 2: Optimized Reverse Iteration
In this approach, we traverse the string from right to left. We add the value of the current character to the total if it is greater or equal to its previous character; otherwise, we subtract it. Reverse traversal helps us intuitively handle the subtraction rule.
def romanToIntFromRight(s: str) -> int:
values = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
total = 0
last_value = 0
for char in reversed(s):
if values[char] < last_value:
total -= values[char]
else:
total += values[char]
last_value = values[char]
return total
print(romanToIntFromRight('MCMXCIV')) # Output: 1994import java.util.HashMap;
import java.util.Map;
public class RomanToIntReverse {
public int romanToIntFromRight(String s) {
Map<Character, Integer> values = new HashMap<>();
values.put('I', 1);
values.put('V', 5);
values.put('X', 10);
values.put('L', 50);
values.put('C', 100);
values.put('D', 500);
values.put('M', 1000);
int total = 0;
int last_value = 0;
for (int i = s.length() - 1; i >= 0; i--) {
int current_value = values.get(s.charAt(i));
if (current_value < last_value) {
total -= current_value;
} else {
total += current_value;
}
last_value = current_value;
}
return total;
}
public static void main(String[] args) {
RomanToIntReverse converter = new RomanToIntReverse();
System.out.println(converter.romanToIntFromRight("MCMXCIV")); // Output: 1994
}
}#include <iostream>
#include <unordered_map>
int romanToIntFromRight(const std::string& s) {
std::unordered_map<char, int> values = {{'I', 1}, {'V', 5}, {'X', 10}, {'L', 50},
{'C', 100}, {'D', 500}, {'M', 1000}};
int total = 0;
int last_value = 0;
for (int i = s.length() - 1; i >= 0; --i) {
int current_value = values[s[i]];
if (current_value < last_value) {
total -= current_value;
} else {
total += current_value;
}
last_value = current_value;
}
return total;
}
int main() {
std::string roman = "LVIII";
std::cout << romanToIntFromRight(roman) << std::endl; // Output: 58
return 0;
}function romanToIntFromRight(s) {
const values = {
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000
};
let total = 0;
let last_value = 0;
for (let i = s.length - 1; i >= 0; i--) {
let current_value = values[s[i]];
if (current_value < last_value) {
total -= current_value;
} else {
total += current_value;
}
last_value = current_value;
}
return total;
}
console.log(romanToIntFromRight('MCMXCIV')); // Output: 1994#include <stdio.h>
#include <string.h>
int romanToIntFromRight(char* s) {
int values[256] = {};
values['I'] = 1;
values['V'] = 5;
values['X'] = 10;
values['L'] = 50;
values['C'] = 100;
values['D'] = 500;
values['M'] = 1000;
int total = 0;
int length = strlen(s);
int last_value = 0;
for (int i = length - 1; i >= 0; i--) {
int current_value = values[s[i]];
if (current_value < last_value) {
total -= current_value;
} else {
total += current_value;
}
last_value = current_value;
}
return total;
}
int main() {
char roman[] = "MCMXCIV";
printf("%d\n", romanToIntFromRight(roman)); // Output: 1994
return 0;
}using System;
using System.Collections.Generic;
class RomanToIntReverse {
public int RomanToIntFromRight(string s) {
Dictionary<char, int> values = new Dictionary<char, int> {
{'I', 1}, {'V', 5}, {'X', 10}, {'L', 50},
{'C', 100}, {'D', 500}, {'M', 1000}
};
int total = 0;
int last_value = 0;
for (int i = s.Length - 1; i >= 0; i--) {
int current_value = values[s[i]];
if (current_value < last_value) {
total -= current_value;
} else {
total += current_value;
}
last_value = current_value;
}
return total;
}
static void Main(string[] args) {
RomanToIntReverse converter = new RomanToIntReverse();
Console.WriteLine(converter.RomanToIntFromRight("LVIII")); // Output: 58
}
}The Python solution traverses the string in reverse to systematically accrue a total based on each character's relation to the last seen one in the sequence.
Time Complexity: O(n).
Space Complexity: O(1).
Approach 3: Hash Table + Simulation
First, we use a hash table d to record the numerical value corresponding to each character. Then, we traverse the string s from left to right. If the numerical value corresponding to the current character is less than the numerical value corresponding to the character on the right, we subtract the numerical value corresponding to the current character. Otherwise, we add the numerical value corresponding to the current character.
The time complexity is O(n), and the space complexity is O(m). Here, n and m are the length of the string s and the size of the character set, respectively.
function romanToInt(s: string): number {
const d: Map<string, number> = new Map([
['I', 1],
['V', 5],
['X', 10],
['L', 50],
['C', 100],
['D', 500],
['M', 1000],
]);
let ans: number = d.get(s[s.length - 1])!;
for (let i = 0; i < s.length - 1; ++i) {
const sign = d.get(s[i])! < d.get(s[i + 1])! ? -1 : 1;
ans += sign * d.get(s[i])!;
}
return ans;
}func romanToInt(s string) (ans int) {
d := map[byte]int{'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
for i := 0; i < len(s)-1; i++ {
if d[s[i]] < d[s[i+1]] {
ans -= d[s[i]]
} else {
ans += d[s[i]]
}
}
ans += d[s[len(s)-1]]
return
}impl Solution {
pub fn roman_to_int(s: String) -> i32 {
let d = vec![
('I', 1),
('V', 5),
('X', 10),
('L', 50),
('C', 100),
('D', 500),
('M', 1000),
]
.into_iter()
.collect::<std::collections::HashMap<_, _>>();
let s: Vec<char> = s.chars().collect();
let mut ans = 0;
let len = s.len();
for i in 0..len - 1 {
if d[&s[i]] < d[&s[i + 1]] {
ans -= d[&s[i]];
} else {
ans += d[&s[i]];
}
}
ans += d[&s[len - 1]];
ans
}
}# @param {String} s
# @return {Integer}
def roman_to_int(s)
d = {
'I' => 1, 'V' => 5, 'X' => 10,
'L' => 50, 'C' => 100,
'D' => 500, 'M' => 1000
}
ans = 0
len = s.length
(0...len-1).each do |i|
if d[s[i]] < d[s[i + 1]]
ans -= d[s[i]]
else
ans += d[s[i]]
end
end
ans += d[s[len - 1]]
ans
endclass Solution {
/**
* @param String $s
* @return Integer
*/
function romanToInt($s) {
$d = [
'I' => 1,
'V' => 5,
'X' => 10,
'L' => 50,
'C' => 100,
'D' => 500,
'M' => 1000,
];
$ans = 0;
$len = strlen($s);
for ($i = 0; $i < $len - 1; $i++) {
if ($d[$s[$i]] < $d[$s[$i + 1]]) {
$ans -= $d[$s[$i]];
} else {
$ans += $d[$s[$i]];
}
}
$ans += $d[$s[$len - 1]];
return $ans;
}
}Complexity comparison
| Approach | Complexity |
|---|---|
| Linear Scan from Left to Right | Time Complexity: O(n). |
| Optimized Reverse Iteration | Time Complexity: O(n). |
| Hash Table + Simulation | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Linear Scan from Left to Right | O(n) | O(1) | Good for explaining Roman subtraction rules clearly during interviews |
| Optimized Reverse Iteration | O(n) | O(1) | Preferred implementation with cleaner logic and no look‑ahead checks |
Frequently asked questions
Is Roman to Integer easy or hard?
Roman to Integer is classified as an Easy problem. The challenge is mainly understanding the subtractive cases such as IV (4) and IX (9). Once that rule is handled, the implementation becomes a straightforward single-pass string traversal.
Roman to Integer Python/Java solution
Most Python and Java solutions define a dictionary or map with the seven Roman symbols and their values, then iterate through the string applying the subtraction rule. Both languages implement the algorithm in O(n) time and O(1) extra space since the mapping size is constant.
How to solve Roman to Integer in O(n)?
Create a mapping from Roman symbols to integer values. Iterate through the string once while applying the subtraction rule: if a symbol is smaller than the one after it (or smaller than the previous symbol in reverse traversal), subtract it; otherwise add it. Because every character is visited once, the algorithm runs in O(n) time.
What is the best approach for Roman to Integer?
The optimized reverse iteration approach is usually considered the best solution. Traverse the string from right to left, keep track of the previous value, and subtract when the current value is smaller. This method processes the string once with O(n) time and O(1) space while keeping the logic concise.
Is Roman to Integer asked at Google/Amazon/Meta?
Roman to Integer appears frequently in coding interview prep lists and has been reported in interview rounds at companies like Amazon and Google for entry-level roles. It tests string traversal, edge case handling, and understanding of simple rule-based parsing.
What data structure is used in Roman to Integer?
A hash table (or dictionary/map) is typically used to store the integer value for each Roman numeral symbol. This allows constant-time lookup when converting characters like I, V, X, L, C, D, and M during the scan of the string.
What is the time complexity of Roman to Integer?
The standard solution runs in O(n) time where n is the length of the Roman numeral string. Each character is processed exactly once with constant-time value lookup from a map. Space complexity stays O(1) because the symbol-to-value mapping contains only seven fixed entries.
