罗马数字转整数

863 字
4 分钟
罗马数字转整数

题目链接:13. 罗马数字转整数 - 力扣(LeetCode)

  • 难度:简单
  • 标签:哈希表、数学、字符串

题目描述#

Note

罗马数字规则: 罗马数字包含以下七种字符: IVXLCDM

字符IVXLCDM
数值1510501005001000

特殊规则: 通常情况下,小的数字在大的数字右边。若小的数字在大的数字左边,则需减去该小数。

  • I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
  • X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
  • C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。

示例#

  • 输入: s = "MCMXCIV"
  • 输出: 1994
  • 解释: M = 1000, CM = 900, XC = 90, IV = 4.

方案一:辅助函数映射法#

核心思路: 遍历字符串,比较当前字符与下一个字符的值。如果当前字符的值比下一个小,说明触发了“减法”规则(如 IV),此时应从总数中减去当前值;否则,加上当前值。

思考过程与坑点#

最初我的代码在处理边界时遇到了问题:

// 典型错误示例:i+1 越界
for(int i = 0; i < s.size(); ++i) {
int a = valueOf(s[i]);
int b = valueOf(s[i+1]); // 当 i 为最后一位时,这里会越界!
if(a < b) total += b - a;
else total += a;
}

改进点

  1. 使用三目运算符处理最后一个字符的 b 值(设为 0)。
  2. b-a 的逻辑简化为:若 a < btotal -= a,否则 total += a

完善后的源码#

class Solution {
public:
int valueOf(char c) {
switch (c) {
case 'I': return 1;
case 'V': return 5;
case 'X': return 10;
case 'L': return 50;
case 'C': return 100;
case 'D': return 500;
case 'M': return 1000;
default: return 0;
}
}
int romanToInt(string s) {
int total = 0;
for (int i = 0; i < s.size(); ++i) {
int a = valueOf(s[i]);
// 使用三目运算符安全处理越界
int b = (i + 1 < s.size()) ? valueOf(s[i + 1]) : 0;
if (a < b) {
total -= a; // 小数在左,减去
} else {
total += a; // 正常情况,加上
}
}
return total;
}
};

方案二:哈希表法(标准解法)#

虽然 switch-case 效率很高,但使用 哈希表(unordered_map) 能够让代码更加简洁且符合现代 C++ 的习惯。

#include <string>
#include <unordered_map>
class Solution {
public:
int romanToInt(std::string s) {
// 使用静态常量哈希表,避免重复构造
static const std::unordered_map<char, int> T = {
{'I', 1}, {'V', 5}, {'X', 10}, {'L', 50},
{'C', 100}, {'D', 500}, {'M', 1000}
};
int total = 0;
for (int i = 0; i < (int)s.size(); ++i) {
int cur = T.at(s[i]);
int nxt = (i + 1 < (int)s.size()) ? T.at(s[i + 1]) : 0;
if (cur < nxt) total -= cur;
else total += cur;
}
return total;
}
};

关键点总结#

  • 三目运算符(i + 1 < s.size()) ? ... : 0 是处理数组/字符串越界非常优雅的方式。
  • 减法逻辑:罗马数字的减法组合(如 IX)可以拆解为 -1 + 10。这比判断两个字符再决定是否跳过一个索引的逻辑要简单得多。
  • 时间复杂度O(n)O(n)。其中 nn 是字符串的长度。我们只需要遍历一遍字符串。
  • 空间复杂度O(1)O(1)
    • 方案一:只使用了常数个额外变量。
    • 方案二:哈希表的大小取决于字符集的大小,本题字符集固定为 7 个罗马数字,因此也是常数空间。

Tip

罗马数字的规则并不多,理清“左小减、右小加”这条核心逻辑,题目就迎刃而解了。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

罗马数字转整数
https://firefly-7a0.pages.dev/posts/leetcode_notes/13roman-to-integer/
作者
lonelystar
发布于
2025-09-27
许可协议
CC BY-NC-SA 4.0
最后更新于 2025-09-27,距今已过 214 天

部分内容可能已过时

评论区

Profile Image of the Author
LonelyStar
Hello, I'm LonelyStar.
公告
欢迎来到我的博客!
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
119
分类
11
标签
346
总字数
226,548
运行时长
0
最后活动
0 天前

目录