罗马数字转整数

哈希表 字符串

题目描述

罗马数字由七个不同的符号组成:

符号
I1
V5
X10
L50
C100
D500
M1000

通常情况下,罗马数字中小的数字在大的数字右边,将它们逐一相加即可得到结果。但有六种特殊的减法情形:

  • IV = 4,IX = 9
  • XL = 40,XC = 90
  • CD = 400,CM = 900

给定一个罗马数字字符串,将其转换为整数。

思路分析

最直接的观察是:当前字符的值小于它右边字符的值时,就需要减去当前值;否则加上当前值。

这个规律覆盖了所有六种减法情形,无需对特殊组合逐一判断。

具体做法:

  1. 建立一张罗马字符到数值的映射表。
  2. 从左到右遍历字符串,对每个字符:
    • 若其值小于下一个字符的值,则将当前值去。
    • 否则将当前值上。
  3. 返回累计结果。

算法步骤

  1. 初始化映射表,将七个罗马字符对应到其整数值。
  2. 初始化累计结果 ans = 0
  3. 遍历字符串,取当前字符的值 value
  4. 判断 value 是否小于下一个字符的值:若是,ans -= value;否则 ans += value
  5. 遍历结束后返回 ans

示例代码

/**
 * 将罗马数字字符串转换为整数
 * @param str 罗马数字字符串,例如 "XIV"
 * @returns 对应的整数值
 */
export function romanToNum(str: string): number {
    // 建立罗马字符到数值的映射表
    const romanMap = new Map([
        ['I', 1],
        ['V', 5],
        ['X', 10],
        ['L', 50],
        ['C', 100],
        ['D', 500],
        ['M', 1000]
    ]);

    let ans = 0;
    const n = str.length;

    for (let i = 0; i < n; i++) {
        // 取当前字符对应的数值,若不在映射表中则为 0
        const value = romanMap.get(str[i]) ?? 0;
        // 若当前值小于下一个字符的值,说明是减法规则(如 IV = 4,IX = 9)
        // 此时应减去当前值;否则正常累加
        if (i < n - 1 && value < (romanMap.get(str[i + 1]) ?? 0)) {
            ans -= value
        } else {
            ans += value;
        }
    }

    return ans;
}

console.log('III', romanToNum('III')) // 3
console.log('IV', romanToNum('IV')) // 4
console.log('IX', romanToNum('IX')) // 9
console.log('LVIII', romanToNum('LVIII')) // 58
console.log('MCMXCIV', romanToNum('MCMXCIV')) // 1994

复杂度分析

  • 时间复杂度O(n),其中 n 是字符串长度,只需一次线性遍历。
  • 空间复杂度O(1),映射表大小固定为 7,与输入规模无关。

示例演示

MCMXCIV(= 1994)为例,逐字符演示:

下标字符当前值下一个值操作累计 ans
0M1000100 (C)+10001000
1C1001000 (M)−100900
2M100010 (X)+10001900
3X10100 (C)−101890
4C1001 (I)+1001990
5I15 (V)−11989
6V5+51994

最终结果为 1994