A film archive stored copyright years as Roman strings on the slate. The ingest job replaced IV, IX, XL, XC, CD, and CM with additive runs, then summed every letter. A weekend of title cards returned in seconds. A century of reels allocated a rewritten string for every row while the catalog window closed.
Roman to Integer asks for the numeric value of a valid Roman numeral string. Each character already has a fixed value. Expanding the six subtractive pairs uses that and still pays six rewrites. One peek at the next value is enough: if the current numeral is smaller, subtract it; otherwise add.
This is an interview writeup, not a grammar of Roman numerals. Here we only care about when a smaller numeral sits before a larger one so the total is a signed walk, not a nested replace.
The problem
Given a string s of Roman numerals, return its integer value. Letters map I=1, V=5, X=10, L=50, C=100, D=500, M=1000. The six subtractive pairs are IV=4, IX=9, XL=40, XC=90, CD=400, CM=900. Assume s is a valid Roman numeral.
s = "III" → 3
s = "LVIII" → 58 L + V + III
s = "MCMXCIV" → 1994 M + CM + XC + IV
Note: Replace the six pairs, then sum, is a legal middle path. It is not the usual interview answer: the prompt did not ask you to rewrite the string, and one comparison with the next value answers in a single pass.
Replace the pairs, then sum, is the honest brute force
Expand each subtractive pair into additive form, then add every letter. IV becomes IIII, CM becomes DCCCC. Correct. Extra linear space for the rewritten string. A nest of startsWith("IV") ifs is the same idea with the pairs hardcoded.
int romanToIntReplace(String s) {
s = s.replace("CM", "DCCCC")
.replace("CD", "CCCC")
.replace("XC", "LXXXX")
.replace("XL", "XXXX")
.replace("IX", "VIIII")
.replace("IV", "IIII");
Map<Character, Integer> val = 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++) {
total += val.get(s.charAt(i));
}
return total;
}
At a copyright year this is a rounding error. At a backfill of the archive you paid six copies for a question a peek answers in place: is the current value smaller than the next?
One pass: subtract when the next numeral is larger
Map each letter to its value. Walk left to right. Let cur be the value of s.charAt(i).
- If there is a next letter and
curis smaller, subtractcur. - Otherwise add
cur.
You never rewrite s. You never skip an index after a subtract: IV is -1 then +5. The last letter has no next, so it is always added.
Walk MCMXCIV:
s = "MCMXCIV"
i=0 M=1000 next C=100 1000>=100 +1000 total=1000
i=1 C=100 next M=1000 100<1000 -100 total=900
i=2 M=1000 next X=10 1000>=10 +1000 total=1900
i=3 X=10 next C=100 10<100 -10 total=1890
i=4 C=100 next I=1 100>=1 +100 total=1990
i=5 I=1 next V=5 1<5 -1 total=1989
i=6 V=5 last +5 total=1994
M + CM + XC + IV is 1000 + 900 + 90 + 4. The Java is that walk:
int romanToInt(String s) {
Map<Character, Integer> val = Map.of(
'I', 1, 'V', 5, 'X', 10, 'L', 50,
'C', 100, 'D', 500, 'M', 1000
);
int total = 0;
int n = s.length();
for (int i = 0; i < n; i++) {
int cur = val.get(s.charAt(i));
if (i + 1 < n && cur < val.get(s.charAt(i + 1))) {
total -= cur;
} else {
total += cur;
}
}
return total;
}
Time is O(n) — one pass, constant-time lookup per index. Space is O(1) for the seven-letter map.
Note: Do not skip the next index after a subtract. Mixing “treat IV as one token of 4” with “sign the current letter” drops V or double-counts it. Pick one proof. The peek-and-sign proof visits every index once.
What interviewers usually poke next
- Right to left. Remember the previous (already processed, right-hand) value. If current is smaller, subtract; else add. Same
O(n), no peek ati + 1. - A 128-slot array instead of a map.
val['M'] = 1000is the same lookup without boxing. Say that if they flinch atMap.of. - Integer to Roman. Greedy from
Mdown through the six pairs. Different prompt; this walk does not emit letters. - Invalid or empty. Constraints usually give a valid numeral of length at least 1. At the board, ask.
intis enough: the largest standard value is 3999.
You are done with this problem when you can say, out loud, why expanding IV into IIII is correct, why a smaller-before-larger pair is a minus on the current letter, and why you must not skip the next index after that minus.