Intuition
Scan left to right, adding each symbol's value — but when a smaller symbol sits directly before a larger one, it's a subtractive pair (like IV = 4), so subtract it instead of adding.
Explanation
Idea
Roman numerals are almost purely additive: XII = 10 + 1 + 1. The only wrinkle is the six subtractive pairs (IV, IX, XL, XC, CD, CM). There's a clean rule that captures all of them without special-casing: a symbol is subtracted exactly when the symbol immediately to its right is larger.
Algorithm
- Map each symbol to its value.
- Walk the string. For symbol
i: ifi+1exists andvalue[s[i]] < value[s[i+1]], subtractvalue[s[i]]; otherwise add it. - Return the running total.
Worked example: "MCMXCIV"
| i | s[i] | next | rule | running total |
|---|---|---|---|---|
| 0 | M=1000 | C=100 | add | 1000 |
| 1 | C=100 | M=1000 | 100 < 1000 → subtract | 900 |
| 2 | M=1000 | X | add | 1900 |
| 3 | X=10 | C=100 | 10 < 100 → subtract | 1890 |
| 4 | C=100 | I | add | 1990 |
| 5 | I=1 | V=5 | 1 < 5 → subtract | 1989 |
| 6 | V=5 | — | add | 1994 |
Result: 1994.
Complexity
- Time: O(n) — one pass.
- Space: O(1) — a fixed symbol table.
Implementation
import java.util.Map;
class Solution {
public int romanToInt(String s) {
Map<Character, Integer> values = Map.of(
'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++) {
int cur = values.get(s.charAt(i));
if (i + 1 < s.length() && cur < values.get(s.charAt(i + 1))) {
total -= cur;
} else {
total += cur;
}
}
return total;
}
}