Full Text
```python
import collections
def int_to_roman(n):
if not isinstance(n, int):
return "Input must be an integer."
if not 0 < n < 4000:
return "Input must be between 1 and 3999."
# Pre-defined and pre-sorted list of Roman numeral values and their symbols.
# This avoids sorting the dictionary on every function call, improving efficiency.
# The order is crucial for the greedy algorithm to work correctly (largest to smallest,
# including subtractive combinations like 900, 400, 90, 40, 9, 4).
roman_map_list = [
(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 = [] # Use a list for efficient string concatenation
for value, numeral in roman_map_list:
if n == 0: # Optimization: if n becomes 0, no need to continue
break
while n >= value:
result.append(numeral)
n -= value
return "".join(result) # Join list elements into a single string
# Test cases
print(f"3 -> {int_to_roman(3)}")
print(f"58 -> {int_to_roman(58)}")
print(f"1994 -> {int_to_roman(1994)}")
print(f"0 -> {int_to_roman(0)}")
print(f"4000 -> {int_to_roman(4000)}")
print(f"-10 -> {int_to_roman(-10)}")
print(f"2024 -> {int_to_roman(2024)}")
print(f"3999 -> {int_to_roman(3999)}")
print(f"1 -> {int_to_roman(1)}")
print(f"Invalid input (string) -> {int_to_roman('abc')}")