第一题:整数转罗马数字
来源:https://leetcode.cn/problems/integer-to-roman/
七个不同的符号代表罗马数字,其值如下:
| 符号 | 值 |
|---|---|
| I | 1 |
| V | 5 |
| X | 10 |
| L | 50 |
| C | 100 |
| D | 500 |
| M | 1000 |
罗马数字是通过添加从最高到最低的小数位值的转换而形成的。将小数位值转换为罗马数字有以下规则:
- 如果该值不是以 4 或 9 开头,请选择可以从输入中减去的最大值的符号,将该符号附加到结果,减去其值,然后将其余部分转换为罗马数字。
- 如果该值以 4 或 9 开头,使用 减法形式 ,表示从以下符号中减去一个符号,例如 4 是 5 (
V) 减 1 (I):IV,9 是 10 (X) 减 1 (I):IX。仅使用以下减法形式:4 (IV),9 (IX),40 (XL),90 (XC),400 (CD) 和 900 (CM)。 - 只有 10 的次方(
I,X,C,M)最多可以连续附加 3 次以代表 10 的倍数。你不能多次附加 5 (V),50 (L) 或 500 (D)。如果需要将符号附加4次,请使用 减法形式。
给定一个整数,将其转换为罗马数字。
这个题关键是读懂题目,就跟模拟一样,我用的是贪心的思想。
python
class Solution:
def intToRoman(self, num: int) -> str:
# 构建值-符号映射表,按值从大到小排列
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"),
]
roman = []
for value, symbol in value_symbols:
# 当当前值 <= num时,重复拼接符号并减去对应值
while num >= value:
roman.append(symbol)
num -= value
if num == 0:
break
return "".join(roman)
核心思想:罗马数字的构成规则是 "大值符号在前,小值在后",我们可以从最大的罗马数字值开始,不断用当前数字减去这个值,并在结果中拼接对应的符号,直到当前数字减到 0。
把所有可能的罗马数字组合(包括 4=IV、9=IX 这类减法形式)都整理成一个降序的映射表,这样我们只需要从大到小遍历这个表,就能一步步拼出结果。
来模拟验证一下:(以3749为例)
1、3749 > 1000,拼接'M',3749-1000=2749
2、2749 > 1000,拼接'M',2749-1000=1749
3、1749 > 1000,拼接'M',1749-1000=749
4、749 > 500,拼接'D',749-500=249
5、249 > 100,拼接'C',249-100=149
6、149 > 100,拼接'C',149-100=49
7、49 > 40,拼接'XL',49-40=9
8、9 9,拼接'IX',9-9=0
最终结果为MMMDCCXLIX,和题目示例输出完全一致。
第二题:罗马数字转整数
来源:https://leetcode.cn/problems/roman-to-integer/description/
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I可以放在V(5) 和X(10) 的左边,来表示 4 和 9。X可以放在L(50) 和C(100) 的左边,来表示 40 和 90。C可以放在D(500) 和M(1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。
python
class Solution:
def romanToInt(self, s: str) -> int:
roman_map = {
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000
}
total = 0
n = len(s)
for i in range(n):
# 如果当前字符的值小于下一个,就减去当前值
if i < n - 1 and roman_map[s[i]] < roman_map[s[i+1]]:
total -= roman_map[s[i]]
else:
total += roman_map[s[i]]
return total
这道题的核心思路是遍历罗马字符串,根据相邻字符的大小关系决定加或减
通常情况下,罗马数字是左大右小(如 VI → 5+1=6),直接相加即可;如果遇到左小右大的情况(如 IV → 5-1=4),就需要用右边的值减去左边的值。
我们可以统一遍历,当当前字符的值小于下一个字符的值时,就减去当前值;否则就加上当前值。
模拟验证一下:(以"IV"和"MCMXCIV"为例)
roman_map = 'IV'
i = 0时,roman_map[0] = I,I = 1,V = 5,I < V,total -= 1,total = -1;
i = 1时,roman_map[1] = V,V = 5,total += 5,total = 4
遍历结束,最终答案为4。
roman_map = 'MCMXCIV'
i = 0时,roman_map[0] = M,M = 1000,M > C(1000 > 100),total += 1000,total = 1000;
i = 1时,roman_map[1] = C,C = 100,C < M(100 < 1000),total -= 100,total = 900;
i = 2时,roman_map[2] = M,M = 1000,M > X(1000 > 10),total += 1000,total = 1900;
i = 3时,roman_map[3] = X,X = 10,X < C(10 < 100),total -= 10,total = 1890;
i = 4时,roman_map[4] = C,C = 100,C > I(100 > 1),total += 100,total = 1990;
i = 5时,roman_map[5] = I,I = 1,I < V(1 < 5),total -= 1,total = 1989;
i = 6时,roman_map[6] = V,V = 5,total += 5,total = 1994。
最终结果为1994。
所得结果与示例一致,搞定。
ok,记录完毕。