代码训练(28)LeetCode之罗马数字
Author: Once Day Date: 2025年6月10日
漫漫长路,才刚刚开始…
全系列文章可参考专栏: 十年代码训练_Once-Day的博客-优快云博客
参考文章:
1. 原题
罗马数字包含以下七种字符:
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。给定一个罗马数字,将其转换成整数。
提示:
1 <= s.length <= 15
s
仅含字符('I', 'V', 'X', 'L', 'C', 'D', 'M')
- 题目数据保证
s
是一个有效的罗马数字,且表示整数在范围[1, 3999]
内- 题目所给测试用例皆符合罗马数字书写规则,不会出现跨位等情况。
- IL 和 IM 这样的例子并不符合题目要求,49 应该写作 XLIX,999 应该写作 CMXCIX 。
- 关于罗马数字的详尽书写规则,可以参考 罗马数字 - 百度百科。
示例 1:
输入: s = "III"
输出: 3
示例 2:
输入: s = "IV"
输出: 4
示例 3:
输入: s = "IX"
输出: 9
示例 4:
输入: s = "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3.
示例 5:
输入: s = "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.
2. 分析
本题目要求将一个给定的罗马数字字符串转换为对应的整数值。罗马数字使用七个基本符号(I, V, X, L, C, D, M)进行表示,不同的符号组合表示不同的数值,而且有特定的规则来表示特定的数值,如 IV 表示 4,IX 表示 9 等。
罗马数字是由七种基本符号构成,每种符号对应一个基本的数值。通常情况下,小的数字放在大的数字右边,表示这些值的累加。然而,如果小的数字放在大的数字左边,则表示大的数减去小的数。这种特例仅限于几种特定的组合。
解题思路:
- 建立映射:首先,我们需要一个映射来存储每个罗马数字字符对应的整数值。
- 遍历字符串:对给定的罗马数字字符串进行遍历,比较当前字符代表的数值与下一个字符代表的数值。
- 加减逻辑处理:如果当前字符代表的数值小于其右边的字符代表的数值,说明这是一个特殊的组合,执行减法操作;否则,执行加法操作。
- 累加结果:将所有得到的结果累加,得到最终的整数值。
分析步骤:
假设输入的罗马数字为 “MCMXCIV”,其转换过程如下:
- M = 1000
- C = 100,因为下一个字符 M = 1000,所以 1000 - 100 = 900
- M = 1000
- X = 10,因为下一个字符 C = 100,所以 100 - 10 = 90
- C = 100
- I = 1,因为下一个字符 V = 5,所以 5 - 1 = 4
- V = 5
最终结果为:1000 + 900 + 90 + 4 = 1994。
性能优化关键点:
- 空间优化:使用一个固定大小的数组来存储有限的映射关系,避免使用复杂的数据结构。
- 时间优化:整个算法只遍历字符串一次,时间复杂度为 O(n),其中 n 是字符串的长度。通过直接访问数组元素来获取映射值,避免了复杂的条件判断和查找操作。
3. 代码实现
#include <stdio.h>
#include <string.h>
int romanToInt(char * s) {
int values[256] = {0};
values['I'] = 1;
values['V'] = 5;
values['X'] = 10;
values['L'] = 50;
values['C'] = 100;
values['D'] = 500;
values['M'] = 1000;
int result = 0;
int len = strlen(s);
for (int i = 0; i < len; i++) {
int value = values[s[i]];
if (i + 1 < len && values[s[i]] < values[s[i + 1]]) {
result -= value;
} else {
result += value;
}
}
return result;
}
int main() {
char roman[] = "MCMXCIV";
printf("Integer of Roman %s is %d\n", roman, romanToInt(roman));
return 0;
}
代码解释:
- 我们定义了一个数组
values
来存储每个罗马数字字符对应的整数值。 - 遍历输入的罗马数字字符串
s
,使用数组直接查找当前字符对应的值。 - 判断当前字符的值是否小于下一个字符的值,如果是,则从结果中减去当前值;否则加上当前值。
- 最后返回累加的结果。
4. 总结
通过这个题目,我们可以学习到如何处理和转换不同的数值表示法。此外,有效使用数据结构(如数组)来优化查找和访问操作,对于提升编程效率和性能有着重要的作用。对于进一步提升编程能力,应当注重算法效率的同时,也要注意代码的可读性和维护性。