Back to blog
Sep 08, 2025
20 min read

Integer to Roman

Seven different symbols represent Roman numerals with the following values: Symbol Value I 1 V 5 X 10 L 50 C 100 D 500 M 1000 Roman numerals are formed by appending the conversions of decimal place values from highest to lowest. Converting a decimal place value into a Roman numeral has the following rules: If the value does not start with 4 or 9, select the symbol of the maximal value that can be subtracted from the input, append that symbol to the result, subtract its value, and convert the remainder to a Roman numeral. If the value starts with 4 or 9 use the subtractive form representing one symbol subtracted from the following symbol, for example, 4 is 1 (I) less than 5 (V): IV and 9 is 1 (I) less than 10 (X): IX. Only the following subtractive forms are used: 4 (IV), 9 (IX), 40 (XL), 90 (XC), 400 (CD) and 900 (CM). Only powers of 10 (I, X, C, M) can be appended consecutively at most 3 times to represent multiples of 10. You cannot append 5 (V), 50 (L), or 500 (D) multiple times. If you need to append a symbol 4 times use the subtractive form. Given an integer, convert it to a Roman numeral.

Difficulty: Medium | Acceptance: 69.22% | Paid: No

Topics: Hash Table, Math, String

Examples

Input

num = 3749

Output

"MMMDCCXLIX"

Explanation

3000 = MMM as 1000 (M) + 1000 (M) + 1000 (M) 700 = DCC as 500 (D) + 100 (C) + 100 (C) 40 = XL as 10 (X) less of 50 (L) 9 = IX as 1 (I) less of 10 (X) Note: 49 is not 1 (I) less of 50 (L) because the conversion is based on decimal places

Input

num = 58

Output

"LVIII"

Explanation

50 = L 8 = VIII

Input

num = 1994

Output

"MCMXCIV"

Explanation

1000 = M 900 = CM 90 = XC 4 = IV

Constraints

- 1 <= num <= 3999

Brute Force Approach

Intuition

The basic idea is to use the largest value Roman numeral symbols first and subtract them from the number until it’s zero. We need to handle special subtractive cases like IV, IX, XL, XC, CD, CM explicitly.

Steps

  • Identify all valid Roman numeral combinations in descending order of their values, including both regular symbols and subtractive cases.
  • Iterate through these values, subtracting the largest possible value from the number and appending the corresponding Roman symbol to the result string.
  • Repeat until the input number becomes zero.
python
class Solution:
    def intToRoman(self, num: int) -> str:
        # Define the mapping from integer values to Roman numeral strings
        # Including both regular symbols and subtractive cases like 4, 9, 40, 90, 400, 900
        values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
        numerals = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
        
        result = []
        
        # Process each value from the highest to the lowest
        for i in range(len(values)):
            # While the current value can be subtracted from num
            while num &gt;= values[i]:
                num -= values[i]
                result.append(numerals[i])
        
        # Join the list into a single string and return
        return ''.join(result)

Complexity

  • Time: O(1) - Since there are a fixed number of iterations based on the limited input range (max 3999), we can consider it constant time.
  • Space: O(1) - We only use a fixed amount of extra space regardless of the input size.
  • Notes: This is often considered O(1) because the number of operations is bounded by a constant, not dependent on the input size in the asymptotic sense.

Digit-by-Digit Approach

Intuition

Instead of processing the whole number, we can process it digit by digit, starting from thousands down to units. For each digit, we can use a lookup table to get the corresponding Roman numeral part.

Steps

  • Break the number into its digits (thousands, hundreds, tens, units).
  • Create lookup tables for each digit place that map numbers 0-9 to their Roman numeral equivalents, considering subtractive forms.
  • Build the result string by concatenating the Roman numeral parts for each digit.
python
class Solution:
    def intToRoman(self, num: int) -> str:
        # Lookup tables for each digit place
        thousands = ["", "M", "MM", "MMM"]
        hundreds = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"]
        tens = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"]
        units = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]
        
        # Extract each digit and use lookup tables
        return (thousands[num // 1000] + 
                hundreds[(num % 1000) // 100] + 
                tens[(num % 100) // 10] + 
                units[num % 10])

Complexity

  • Time: O(1) - As the number of operations is constant and independent of the input value.
  • Space: O(1) - We use a fixed-size lookup table, so the space complexity is constant.
  • Notes: This approach is very efficient since it directly computes the result without looping. It’s a classic example of trading space for time.

Greedy Subtraction

Intuition

This is a greedy algorithm where at each step we subtract the largest possible Roman numeral value. It’s similar to the brute force but emphasizes that we’re making a locally optimal choice at each step.

Steps

  • Create a list of value-symbol pairs in descending order, including subtractive cases.
  • Iterate through this list, and for each pair, repeatedly subtract the value from the number and append the symbol to the result as long as the value is less than or equal to the current number.
  • Continue until the number becomes zero.
python
class Solution:
    def intToRoman(self, num: int) -> str:
        # Define the value-symbol pairs in descending order
        value_symbols = [
            (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")
        ]
        
        result = []
        
        # Process each pair from the largest to the smallest
        for value, symbol in value_symbols:
            # Add the symbol while the value can be subtracted from num
            count = num // value
            if count:
                result.append(symbol * count)
                num -= value * count
                
        # Join the list into a single string and return
        return ''.join(result)

Complexity

  • Time: O(1) - The number of operations is bounded by a constant due to the fixed input range.
  • Space: O(1) - We use a fixed amount of extra space regardless of the input size.
  • Notes: This is essentially the same as the brute force approach, but framed as a greedy algorithm.