Converting Roman Numerals to Integers: Implementation and Comparison
Roman numerals utilize seven specific symbols: I, V, X, L, C, D, and M. Their corresponding values are:
| Symbol | Value |
|---|---|
| I | 1 |
| V | 5 |
| X | 10 |
| L | 50 |
| C | 100 |
| D | 500 |
| M | 1000 |
Numbers are formed by combining these symbols, typically written from largest to smallest value from left to right. For instance, "XII" represents X + II, equaling 12.
However, a subtractive principle applies in six specific cases to avoid repeating a symbol four times:
Iplaced beforeV(5) orX(10) makes 4 (IV) and 9 (IX).Xplaced beforeL(50) orC(100) makes 40 (XL) and 90 (XC).Cplaced beforeD(500) orM(1000) makes 400 (CD) and 900 (CM).
The objective is to convert a given Roman numeral string to its integer equivaelnt.
Test Cases
- Input:
"III"→ Output:3 - Input:
"IV"→ Output:4 - Input:
"IX"→ Output:9 - Input:
"LVIII"→ Output:58(L=50, V=5, III=3) - Input:
"MCMXCIV"→ Output:1994(M=1000, CM=900, XC=90, IV=4)
Solution Approaches
Approach 1: Look-Ahead Substring Mapping
This method iterates through the string, examining potential two-character combinations first. A dictionary stores all fundamental symbols and the six special compound numerals. For each position i, if i+1 is within bounds, a two-character substring is formed. If this substring exists in the dictionary, its value is added to the total and the index advances by 2. Otherwise, the single character at i is mapped and added, advancing the index by 1.
Java Implemantation
import java.util.HashMap;
class RomanNumeralDecoder {
public int convert(String romanStr) {
HashMap<String, Integer> valueMap = new HashMap<>() {{
put("I", 1);
put("V", 5);
put("X", 10);
put("L", 50);
put("C", 100);
put("D", 500);
put("M", 1000);
put("IV", 4);
put("IX", 9);
put("XL", 40);
put("XC", 90);
put("CD", 400);
put("CM", 900);
}};
int idx = 0;
int total = 0;
while (idx < romanStr.length()) {
if (idx + 1 < romanStr.length()) {
String dualChar = romanStr.substring(idx, idx + 2);
if (valueMap.containsKey(dualChar)) {
total += valueMap.get(dualChar);
idx += 2;
continue;
}
}
total += valueMap.get(romanStr.substring(idx, idx + 1));
idx++;
}
return total;
}
}
Approach 2: Sequential Value Comparison
This method leverages the rule that subtractive notation (e.g., IV) occurs when a smaller value precedes a larger one. The algorithm sequentially processes each symbol. It maintains the value of the previous symbol. For the current symbol's value:
- If the currrent value is greater than the
previousvalue, it indicates a subtractive pair (likeIV). Therefore, thepreviousvalue is subtracted from the running total. - If the current value is less than or equal to the
previousvalue, thepreviousvalue is added to the total (as it belongs to a normal descending sequence). Finally, the last symbol's value is added to the total after the loop.
Java Implementation
class RomanNumeralConverter {
public int romanToInteger(String romanStr) {
int result = 0;
int priorVal = mapCharToValue(romanStr.charAt(0));
for (int pos = 1; pos < romanStr.length(); pos++) {
int currentVal = mapCharToValue(romanStr.charAt(pos));
if (currentVal > priorVal) {
result -= priorVal;
} else {
result += priorVal;
}
priorVal = currentVal;
}
result += priorVal;
return result;
}
private int mapCharToValue(char symbol) {
return switch (symbol) {
case 'I' -> 1;
case 'V' -> 5;
case 'X' -> 10;
case 'L' -> 50;
case 'C' -> 100;
case 'D' -> 500;
case 'M' -> 1000;
default -> 0;
};
}
}
Both approaches correctly handle standard and subtractive Roman numeral patterns, with the second method often being more space-efficient.