#13 数学模拟 简单

罗马数字转整数

在 LeetCode 上查看 ↗

🎧 语音讲解

开车或通勤时可听,跟着思路走一遍

速度

📋 题目描述

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

字符数值
I1
V5
X10
L50
C100
D500
M1000

通常情况下,小的数字在大的数字右边;但若小的数字在大的数字左边,则表示减去该值(如 IV=4,IX=9)。该减法规则仅适用于六种情况:IV/X 前、XL/C 前、CD/M 前。

给定一个罗马数字,将其转换成整数。

示例 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。

💭 模拟答题者思考

1. 最直接:把每个字符的值查表直接相加——IV 会变成 1+5=6,显然错了。

2. 找重复:减法形式都是「小字符在大字符左边」,如 IV 前表示 5-1=4。只需处理这 6 种特例?可以,但要写一堆 if s[i:i+2] in ...,冗长且难维护。

3. 统一规则:从左到右扫,若 roman[s[i]] < roman[s[i+1]],说明当前位被「借走」做减法,ans -= roman[s[i]];否则正常累加。这样 IVIXCM 等全部自动处理。

4. 另一种等价写法是从右往左扫:若当前值 < 已处理的右边值就减,否则加——思路相同,选一种写顺手的即可。

5. 复杂度:字符串最长 15,一次线性扫描 O(n),哈希表 O(1) 空间,足够高效。

🧠 变量语义(先读这三句再编码)

变量类型语义(三句法)
romandict定义:字符到数值的映射表(I→1, V→5, …, M→1000)
维护:固定不变,覆盖全部 7 种符号
更新:无需更新,查询 roman[s[i]] 即可
ansint定义:从左到右扫描后累计的整数值
维护:每处理一个字符,按「加或减」规则更新
更新:若当前字符值 < 下一字符值则 ans -= val,否则 ans += val
iint定义:当前扫描到的字符下标
维护:从 0 遍历到 len(s)-1,每次右移一位
更新i++;判断减法时需偷看 s[i+1]

⌨️ 落码步骤

1. 建立 roman 字符→数值映射表

2. 初始化 ans = 0,从左到右遍历下标 i

3. 取 val = roman[s[i]];若 i+1 < len(s)val < roman[s[i+1]],则 ans -= val,否则 ans += val

4. 遍历结束返回 ans

💻 代码实现

class Solution:
    def romanToInt(self, s: str) -> int:
        roman = {"I": 1, "V": 5, "X": 10, "L": 50,
                 "C": 100, "D": 500, "M": 1000}
        ans = 0
        for i in range(len(s)):
            val = roman[s[i]]
            # 当前位比右边小 → 减法形式(如 I 在 V 前)
            if i + 1 < len(s) and val < roman[s[i + 1]]:
                ans -= val
            else:
                ans += val
        return ans
class Solution {
public:
    int romanToInt(string s) {
        unordered_map<char, int> roman = {
            {'I', 1}, {'V', 5}, {'X', 10}, {'L', 50},
            {'C', 100}, {'D', 500}, {'M', 1000}
        };
        int ans = 0;
        for (int i = 0; i < (int)s.size(); ++i) {
            int val = roman[s[i]];
            if (i + 1 < (int)s.size() && val < roman[s[i + 1]]) {
                ans -= val;
            } else {
                ans += val;
            }
        }
        return ans;
    }
};
// 时间 O(n),空间 O(1)

📈 复杂度分析

时间复杂度 O(n)
空间复杂度 O(1)

⚠️ 常见坑

不能对所有字符直接求和,否则 IV 会得到 6 而非 4。

判断减法时要比较数值而非字符 ASCII(虽然本题数据下碰巧一致,但语义上应查表比较)。

遍历时注意边界:最后一位没有「下一字符」,永远做加法。

🔍 必测边界 Case

Case 1:纯加法
s = "III" → 3
Case 2:单位减法
s = "IV" → 4s = "IX" → 9
Case 3:复合串
s = "MCMXCIV" → 1994(同时含 CM、XC、IV 三种减法形式)