diff --git a/conversions/roman_numerals.py b/conversions/roman_numerals.py index 75af2ac72..422c4ead6 100644 --- a/conversions/roman_numerals.py +++ b/conversions/roman_numerals.py @@ -1,61 +1,56 @@ ROMAN = [ - (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"), + (1000000, "M_"), (900000, "C_M_"), (500000, "D_"), (400000, "C_D_"), + (100000, "C_"), (90000, "X_C_"), (50000, "L_"), (40000, "X_L_"), + (10000, "X_"), (9000, "I_X_"), (5000, "V_"), (4000, "I_V_"), + (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") ] - - def roman_to_int(roman: str) -> int: """ - LeetCode No. 13 Roman to Integer - Given a roman numeral, convert it to an integer. - Input is guaranteed to be within the range from 1 to 3999. - https://en.wikipedia.org/wiki/Roman_numerals - >>> tests = {"III": 3, "CLIV": 154, "MIX": 1009, "MMD": 2500, "MMMCMXCIX": 3999} + Convert a Roman numeral to an integer, supporting Vinculum notation (underscore _ represents 1000 times). + LeetCode No. 13 Roman to Integer + ​    Given a roman numeral, convert it to an integer. + ​    Input is guaranteed to be within the range from 1 to 3999. + ​    https://en.wikipedia.org/wiki/Roman_numerals + ​    >>> all(roman_to_int(key) == value for key, value in tests.items()) + >>> tests = {"III": 3, "CLIV": 154, "MIX": 1009, "MMD": 2500, "MMMCMXCIX": 3999, "I_V_": 4000, "X_": 10000, "M_": 1000000} >>> all(roman_to_int(key) == value for key, value in tests.items()) True """ - vals = {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000} - total = 0 - place = 0 - while place < len(roman): - if (place + 1 < len(roman)) and (vals[roman[place]] < vals[roman[place + 1]]): - total += vals[roman[place + 1]] - vals[roman[place]] - place += 2 + vals = { + "I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000, + "I_": 1000, "V_": 5000, "X_": 10000, "L_": 50000, "C_": 100000, "D_": 500000, "M_": 1000000 + } + i, total = 0, 0 + while i < len(roman): + if i + 1 < len(roman) and (roman[i:i+2] in vals): # 处理 `_` 记法 + total += vals[roman[i:i+2]] + i += 2 else: - total += vals[roman[place]] - place += 1 + total += vals[roman[i]] + i += 1 return total - - -def int_to_roman(number: int) -> str: + def int_to_roman(number: int) -> str: """ - Given a integer, convert it to an roman numeral. - https://en.wikipedia.org/wiki/Roman_numerals - >>> tests = {"III": 3, "CLIV": 154, "MIX": 1009, "MMD": 2500, "MMMCMXCIX": 3999} + Convert an integer to a Roman numeral, supporting Vinculum notation (underscore _ represents 1000 times). +  Given a integer, convert it to an roman numeral. + ​    https://en.wikipedia.org/wiki/Roman_numerals + >>> tests = {"III": 3, "CLIV": 154, "MIX": 1009, "MMD": 2500, "MMMCMXCIX": 3999, "I_V_": 4000, "X_": 10000, "M_": 1000000} >>> all(int_to_roman(value) == key for key, value in tests.items()) True """ + if not isinstance(number, int) or number < 1: + raise ValueError("Input must be a positive integer greater than 0") + result = [] for arabic, roman in ROMAN: - (factor, number) = divmod(number, arabic) + factor, number = divmod(number, arabic) result.append(roman * factor) if number == 0: - break + reak return "".join(result) - if __name__ == "__main__": import doctest - doctest.testmod()