Convert an integer (1–3999) to a Roman numeral. The whole trick is the lookup table: order the value→symbol pairs descending and include the six subtractive forms (CM, CD, XC, XL, IX, IV) as first-class entries, then greedily subtract.
Convert an integer num (1 to 3999) into its Roman numeral string. Roman numerals use I, V, X, L, C, D, M, written largest-to-smallest and summed — except for six subtractive pairs (IV, IX, XL, XC, CD, CM). Example: num = 1994 → "MCMXCIV" (M=1000, CM=900, XC=90, IV=4). Example: num = 58 → "LVIII" (L=50, V=5, III=3).
[1000 M, 900 CM, 500 D, 400 CD, 100 C, 90 XC, 50 L, 40 XL, 10 X, 9 IX, 5 V, 4 IV, 1 I]. Now it's a plain greedy: repeatedly take the largest value that still fits, append its symbol, subtract it, until num hits zero.num >= value, you can place that symbol — because the table is sorted, the first entry that fits is always the largest legal one (greedy is optimal here).result += symbol then num -= value. Repeat the while-loop so e.g. 30 places X three times.num reaches 0, result is the answer. Because 1 I is in the table, this always terminates.IV/IX by hand. That works but is bug-prone. Once the subtractive pairs live in the table, there are no special cases — a 4 simply means the 4 IV entry fits and the 5 Vone didn't.Both are effectively O(1): the table has 13 fixed entries and the answer has at most ~15 characters (e.g. 3888 = MMMDCCCLXXXVIII), so the loop body runs a constant-bounded number of times. Space is O(1) beyond the output string.
1994. Walk the value→symbol table from largest to smallest, greedily subtracting the largest value that still fits. The subtractive pairs (CM, CD, XC, XL, IX, IV) are baked into the table.1function intToRoman(num: number): string {2▶ const values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];3▶ const symbols = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];45▶ let result = '';67 for (let i = 0; i < values.length; i++) {8 while (num >= values[i]) { // largest value that still fits9 result += symbols[i]; // append its symbol10 num -= values[i]; // subtract it off11 }12 }1314 return result;15}
function intToRoman(num: number): string {
// Table ordered DESC, with subtractive pairs inlined.
const values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
const symbols = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
let result = '';
for (let i = 0; i < values.length; i++) {
while (num >= values[i]) { // largest value that still fits
result += symbols[i]; // append its symbol
num -= values[i]; // subtract it off
}
}
return result;
}descending, with the subtractive pairs (CM, CD, XC, XL, IX, IV) sitting right next to their non-subtractive neighbours. This table is the whole algorithm.resultstarts empty and only ever grows by appending symbols left to right, so it's already in the correct order.num >= values[i], append symbols[i] and subtract values[i]. The while (not if) lets a single entry repeat — e.g. 30 emits XXX, 3000 emits MMM.num is 0 and result holds the full numeral. Having 1 I in the table guarantees the loop always drains num completely.num ≤ 3999, so the total number of appended symbols is bounded by a small constant (≤ 15).function intToRoman(num: number): string {
// Table ordered DESC, with subtractive pairs inlined.
const values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
const symbols = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
let result = '';
for (let i = 0; i < values.length; i++) {
while (num >= values[i]) { // largest value that still fits
result += symbols[i]; // append its symbol
num -= values[i]; // subtract it off
}
}
return result;
}num ≤ 3999, so the total number of appended symbols is bounded by a small constant (≤ 15).Precompute the Roman string for each digit in each place (ones, tens, hundreds, thousands), then concatenate the four lookups.
function intToRoman(num: number): string {
const thousands = ['', 'M', 'MM', 'MMM'];
const hundreds = ['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'];
const tens = ['', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'];
const ones = ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'];
return (
thousands[Math.floor(num / 1000)] +
hundreds[Math.floor(num / 100) % 10] +
tens[Math.floor(num / 10) % 10] +
ones[num % 10]
);
}| integer → Roman numeral | descending value→symbol table + greedy subtract |
| subtractive forms (IV, IX, XL…) | add them as 6 extra table entries |
| canonical coin system, fewest tokens | greedy take-largest-that-fits |
| repeat the same symbol (XXX, MMM) | inner while, not if |
function intToRoman(num: number): string {
const values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
const symbols = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
let result = '';
for (let i = 0; i < values.length; i++) {
while (num >= values[i]) {
result += symbols[i];
num -= values[i];
}
}
return result;
}num = 1994, what is the output?num = 58 produce?