|
1 | 1 | ROMAN = [ |
2 | | - (1000, "M"), |
3 | | - (900, "CM"), |
4 | | - (500, "D"), |
5 | | - (400, "CD"), |
6 | | - (100, "C"), |
7 | | - (90, "XC"), |
8 | | - (50, "L"), |
9 | | - (40, "XL"), |
10 | | - (10, "X"), |
11 | | - (9, "IX"), |
12 | | - (5, "V"), |
13 | | - (4, "IV"), |
14 | | - (1, "I"), |
| 2 | + (1000000, "M_"), (900000, "C_M_"), (500000, "D_"), (400000, "C_D_"), |
| 3 | + (100000, "C_"), (90000, "X_C_"), (50000, "L_"), (40000, "X_L_"), |
| 4 | + (10000, "X_"), (9000, "I_X_"), (5000, "V_"), (4000, "I_V_"), |
| 5 | + (1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), |
| 6 | + (100, "C"), (90, "XC"), (50, "L"), (40, "XL"), |
| 7 | + (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I") |
15 | 8 | ] |
16 | | - |
17 | | - |
18 | 9 | def roman_to_int(roman: str) -> int: |
19 | 10 | """ |
20 | | - LeetCode No. 13 Roman to Integer |
21 | | - Given a roman numeral, convert it to an integer. |
22 | | - Input is guaranteed to be within the range from 1 to 3999. |
23 | | - https://en.wikipedia.org/wiki/Roman_numerals |
24 | | - >>> tests = {"III": 3, "CLIV": 154, "MIX": 1009, "MMD": 2500, "MMMCMXCIX": 3999} |
| 11 | + Convert a Roman numeral to an integer, supporting Vinculum notation (underscore _ represents 1000 times). |
| 12 | + LeetCode No. 13 Roman to Integer |
| 13 | + Given a roman numeral, convert it to an integer. |
| 14 | + Input is guaranteed to be within the range from 1 to 3999. |
| 15 | + https://en.wikipedia.org/wiki/Roman_numerals |
| 16 | + >>> all(roman_to_int(key) == value for key, value in tests.items()) |
| 17 | + >>> tests = {"III": 3, "CLIV": 154, "MIX": 1009, "MMD": 2500, "MMMCMXCIX": 3999, "I_V_": 4000, "X_": 10000, "M_": 1000000} |
25 | 18 | >>> all(roman_to_int(key) == value for key, value in tests.items()) |
26 | 19 | True |
27 | 20 | """ |
28 | | - vals = {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000} |
29 | | - total = 0 |
30 | | - place = 0 |
31 | | - while place < len(roman): |
32 | | - if (place + 1 < len(roman)) and (vals[roman[place]] < vals[roman[place + 1]]): |
33 | | - total += vals[roman[place + 1]] - vals[roman[place]] |
34 | | - place += 2 |
| 21 | + vals = { |
| 22 | + "I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000, |
| 23 | + "I_": 1000, "V_": 5000, "X_": 10000, "L_": 50000, "C_": 100000, "D_": 500000, "M_": 1000000 |
| 24 | + } |
| 25 | + i, total = 0, 0 |
| 26 | + while i < len(roman): |
| 27 | + if i + 1 < len(roman) and (roman[i:i+2] in vals): # 处理 `_` 记法 |
| 28 | + total += vals[roman[i:i+2]] |
| 29 | + i += 2 |
35 | 30 | else: |
36 | | - total += vals[roman[place]] |
37 | | - place += 1 |
| 31 | + total += vals[roman[i]] |
| 32 | + i += 1 |
38 | 33 | return total |
39 | | - |
40 | | - |
41 | | -def int_to_roman(number: int) -> str: |
| 34 | + def int_to_roman(number: int) -> str: |
42 | 35 | """ |
43 | | - Given a integer, convert it to an roman numeral. |
44 | | - https://en.wikipedia.org/wiki/Roman_numerals |
45 | | - >>> tests = {"III": 3, "CLIV": 154, "MIX": 1009, "MMD": 2500, "MMMCMXCIX": 3999} |
| 36 | + Convert an integer to a Roman numeral, supporting Vinculum notation (underscore _ represents 1000 times). |
| 37 | + Given a integer, convert it to an roman numeral. |
| 38 | + https://en.wikipedia.org/wiki/Roman_numerals |
| 39 | + >>> tests = {"III": 3, "CLIV": 154, "MIX": 1009, "MMD": 2500, "MMMCMXCIX": 3999, "I_V_": 4000, "X_": 10000, "M_": 1000000} |
46 | 40 | >>> all(int_to_roman(value) == key for key, value in tests.items()) |
47 | 41 | True |
48 | 42 | """ |
| 43 | + if not isinstance(number, int) or number < 1: |
| 44 | + raise ValueError("Input must be a positive integer greater than 0") |
| 45 | + |
49 | 46 | result = [] |
50 | 47 | for arabic, roman in ROMAN: |
51 | | - (factor, number) = divmod(number, arabic) |
| 48 | + factor, number = divmod(number, arabic) |
52 | 49 | result.append(roman * factor) |
53 | 50 | if number == 0: |
54 | | - break |
| 51 | + reak |
55 | 52 | return "".join(result) |
56 | 53 |
|
57 | | - |
58 | 54 | if __name__ == "__main__": |
59 | 55 | import doctest |
60 | | - |
61 | 56 | doctest.testmod() |
0 commit comments