🧠
Better (Precompute Subtractive Pairs and Use Greedy Parsing)
💡 This approach improves clarity by explicitly checking for known subtractive pairs first, then adding values for single symbols. It reduces conditional complexity and makes the code easier to reason about.
Intuition
Scan the string left to right, at each step check if the next two characters form a known subtractive pair. If yes, add the pair's value and skip two characters; else add the single symbol's value and move one character.
Algorithm
- Create a map for single Roman symbols and a map for subtractive pairs.
- Initialize result to 0 and index i to 0.
- While i < length of string:
- Check if substring s[i:i+2] is a subtractive pair; if yes, add its value and increment i by 2.
- Otherwise, add value of s[i] and increment i by 1.
- Return the accumulated result.
💡 This approach is easier to debug because it separates subtractive pairs from single symbols explicitly.
def romanToInt(s: str) -> int:
single_map = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
pair_map = {'IV': 4, 'IX': 9, 'XL': 40, 'XC': 90, 'CD': 400, 'CM': 900}
result = 0
i = 0
while i < len(s):
if i + 1 < len(s) and s[i:i+2] in pair_map:
result += pair_map[s[i:i+2]]
i += 2
else:
result += single_map[s[i]]
i += 1
return result
# Driver code
if __name__ == '__main__':
test_cases = ['III', 'IV', 'IX', 'LVIII', 'MCMXCIV']
for tc in test_cases:
print(f'{tc} -> {romanToInt(tc)}')
Line Notes
single_map = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}Maps single Roman numerals to their integer values.
pair_map = {'IV': 4, 'IX': 9, 'XL': 40, 'XC': 90, 'CD': 400, 'CM': 900}Maps known subtractive pairs to their integer values.
while i < len(s)Iterates through the string using an index to allow skipping characters.
if i + 1 < len(s) and s[i:i+2] in pair_mapChecks if the next two characters form a subtractive pair.
result += pair_map[s[i:i+2]]Adds the value of the subtractive pair to the result.
i += 2Skips two characters after processing a pair.
else:Handles the case when no subtractive pair is found.
result += single_map[s[i]]Adds the value of a single symbol when no pair is found.
i += 1Moves to the next character.
import java.util.*;
public class RomanToInteger {
public static int romanToInt(String s) {
Map<String, Integer> pairMap = new HashMap<>();
pairMap.put("IV", 4);
pairMap.put("IX", 9);
pairMap.put("XL", 40);
pairMap.put("XC", 90);
pairMap.put("CD", 400);
pairMap.put("CM", 900);
Map<Character, Integer> singleMap = new HashMap<>();
singleMap.put('I', 1);
singleMap.put('V', 5);
singleMap.put('X', 10);
singleMap.put('L', 50);
singleMap.put('C', 100);
singleMap.put('D', 500);
singleMap.put('M', 1000);
int result = 0;
int i = 0;
while (i < s.length()) {
if (i + 1 < s.length() && pairMap.containsKey(s.substring(i, i + 2))) {
result += pairMap.get(s.substring(i, i + 2));
i += 2;
} else {
result += singleMap.get(s.charAt(i));
i++;
}
}
return result;
}
public static void main(String[] args) {
String[] testCases = {"III", "IV", "IX", "LVIII", "MCMXCIV"};
for (String tc : testCases) {
System.out.println(tc + " -> " + romanToInt(tc));
}
}
}
Line Notes
Map<String, Integer> pairMap = new HashMap<>();Stores subtractive pairs and their values for quick lookup.
Map<Character, Integer> singleMap = new HashMap<>();Stores single Roman numeral values.
while (i < s.length())Uses a while loop to allow skipping characters when pairs are found.
if (i + 1 < s.length() && pairMap.containsKey(s.substring(i, i + 2)))Checks if the next two characters form a subtractive pair.
result += pairMap.get(s.substring(i, i + 2));Adds the value of the subtractive pair.
i += 2;Skips two characters after processing a pair.
else {Handles the case when no subtractive pair is found.
result += singleMap.get(s.charAt(i));Adds single symbol value.
i++;Moves forward by one character.
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;
int romanToInt(string s) {
unordered_map<string, int> pairMap = {{"IV",4},{"IX",9},{"XL",40},{"XC",90},{"CD",400},{"CM",900}};
unordered_map<char, int> singleMap = {{'I',1},{'V',5},{'X',10},{'L',50},{'C',100},{'D',500},{'M',1000}};
int result = 0;
int i = 0;
while (i < s.size()) {
if (i + 1 < s.size() && pairMap.count(s.substr(i, 2))) {
result += pairMap[s.substr(i, 2)];
i += 2;
} else {
result += singleMap[s[i]];
i++;
}
}
return result;
}
int main() {
string testCases[] = {"III", "IV", "IX", "LVIII", "MCMXCIV"};
for (auto &tc : testCases) {
cout << tc << " -> " << romanToInt(tc) << endl;
}
return 0;
}
Line Notes
unordered_map<string, int> pairMap = {{"IV",4},{"IX",9},{"XL",40},{"XC",90},{"CD",400},{"CM",900}};Maps subtractive pairs to their integer values.
unordered_map<char, int> singleMap = {{'I',1},{'V',5},{'X',10},{'L',50},{'C',100},{'D',500},{'M',1000}};Maps single Roman numerals to values.
while (i < s.size())Iterates through the string with index i, allowing skipping characters.
if (i + 1 < s.size() && pairMap.count(s.substr(i, 2)))Checks if the next two characters form a subtractive pair.
result += pairMap[s.substr(i, 2)];Adds the value of the subtractive pair.
i += 2;Skips two characters after processing a pair.
else {Handles the case when no subtractive pair is found.
result += singleMap[s[i]];Adds single symbol value.
i++;Moves forward by one character.
function romanToInt(s) {
const pairMap = {'IV':4, 'IX':9, 'XL':40, 'XC':90, 'CD':400, 'CM':900};
const singleMap = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000};
let result = 0;
let i = 0;
while (i < s.length) {
if (i + 1 < s.length && pairMap[s.substring(i, i + 2)]) {
result += pairMap[s.substring(i, i + 2)];
i += 2;
} else {
result += singleMap[s[i]];
i++;
}
}
return result;
}
// Test cases
const testCases = ['III', 'IV', 'IX', 'LVIII', 'MCMXCIV'];
testCases.forEach(tc => console.log(`${tc} -> ${romanToInt(tc)}`));
Line Notes
const pairMap = {'IV':4, 'IX':9, 'XL':40, 'XC':90, 'CD':400, 'CM':900};Stores subtractive pairs and their values.
const singleMap = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000};Stores single Roman numeral values.
while (i < s.length)Uses a while loop to allow skipping characters when pairs are found.
if (i + 1 < s.length && pairMap[s.substring(i, i + 2)])Checks if the next two characters form a subtractive pair.
result += pairMap[s.substring(i, i + 2)];Adds the value of the subtractive pair.
i += 2;Skips two characters after processing a pair.
else {Handles the case when no subtractive pair is found.
result += singleMap[s[i]];Adds single symbol value.
i++;Moves forward by one character.
Each character is processed once or twice in the worst case, with constant time map lookups.
💡 For n=15, this approach performs at most 15 iterations, making it very efficient.
Interview Verdict: Accepted
This approach is clean and efficient, often preferred for clarity in interviews.