LeetCode 经典题:“罗马数字转整数”

一、题目描述

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

字符数值
I1
V5
X10
L50
C100
D500
M1000

例如, 罗马数字 2 写做 II ,即为两个并列的 112 写做 XII ,即为 X + II27 写做 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 到 3999 的范围内。

示例

  • 示例 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 and IV = 4.

二、解题思路与多方法实现

方法一:常规遍历法

思路
  1. 首先,我们需要创建一个映射,将罗马字符和对应的整数值关联起来。
  2. 然后,从左到右遍历罗马数字字符串。对于每个字符,我们获取其对应的整数值。
  3. 接着,判断当前字符对应的数值是否小于下一个字符对应的数值。如果是,说明遇到了特殊情况(如 IVIX 等),此时需要用下一个字符的数值减去当前字符的数值,并将索引向后移动两位;否则,直接将当前字符的数值累加到结果中,并将索引向后移动一位。
代码实现(Java)
import java.util.HashMap;
import java.util.Map;

public class RomanToInteger {
    public int romanToInt(String s) {
        // 创建罗马字符到整数值的映射
        Map<Character, Integer> romanMap = new HashMap<>();
        romanMap.put('I', 1);
        romanMap.put('V', 5);
        romanMap.put('X', 10);
        romanMap.put('L', 50);
        romanMap.put('C', 100);
        romanMap.put('D', 500);
        romanMap.put('M', 1000);

        int result = 0;
        int i = 0;
        while (i < s.length()) {
            int currentValue = romanMap.get(s.charAt(i));
            if (i + 1 < s.length()) {
                int nextValue = romanMap.get(s.charAt(i + 1));
                if (currentValue < nextValue) {
                    // 特殊情况,如 IV、IX 等
                    result += nextValue - currentValue;
                    i += 2;
                } else {
                    result += currentValue;
                    i++;
                }
            } else {
                // 最后一个字符
                result += currentValue;
                i++;
            }
        }
        return result;
    }
}
代码解释
  1. 创建映射:使用 HashMap 存储罗马字符和对应的整数值,方便后续查找。
  2. 遍历字符串:使用 while 循环遍历罗马数字字符串。对于每个字符,获取其对应的整数值 currentValue
  3. 特殊情况判断:检查是否存在下一个字符,如果存在,获取下一个字符的数值 nextValue。若 currentValue < nextValue,说明是特殊情况,将 nextValue - currentValue 累加到结果中,并将索引 i 向后移动两位;否则,直接将 currentValue 累加到结果中,并将索引 i 向后移动一位。
  4. 处理最后一个字符:当遍历到最后一个字符时,直接将其对应的数值累加到结果中。

方法二:逆序遍历法

思路
  1. 同样先创建罗马字符和整数值的映射。
  2. 从右到左逆序遍历罗马数字字符串。对于每个字符,获取其对应的整数值。
  3. 比较当前字符对应的数值和前一个处理过的字符对应的数值。如果当前字符的数值小于前一个处理过的字符的数值,说明是特殊情况,需要从结果中减去当前字符的数值;否则,将当前字符的数值累加到结果中。
代码实现(Java)
import java.util.HashMap;
import java.util.Map;

public class RomanToIntegerReverse {
    public int romanToInt(String s) {
        // 创建罗马字符到整数值的映射
        Map<Character, Integer> romanMap = new HashMap<>();
        romanMap.put('I', 1);
        romanMap.put('V', 5);
        romanMap.put('X', 10);
        romanMap.put('L', 50);
        romanMap.put('C', 100);
        romanMap.put('D', 500);
        romanMap.put('M', 1000);

        int result = 0;
        int prevValue = 0;
        for (int i = s.length() - 1; i >= 0; i--) {
            int currentValue = romanMap.get(s.charAt(i));
            if (currentValue < prevValue) {
                result -= currentValue;
            } else {
                result += currentValue;
            }
            prevValue = currentValue;
        }
        return result;
    }
}
代码解释
  1. 创建映射:和方法一一样,使用 HashMap 存储罗马字符和对应的整数值。
  2. 逆序遍历字符串:使用 for 循环从右到左遍历罗马数字字符串。对于每个字符,获取其对应的整数值 currentValue
  3. 特殊情况判断:比较 currentValueprevValue(前一个处理过的字符的数值)。如果 currentValue < prevValue,说明是特殊情况,从结果中减去 currentValue;否则,将 currentValue 累加到结果中。
  4. 更新前一个值:每次处理完一个字符后,将 prevValue 更新为 currentValue

三、复杂度分析

时间复杂度

  • 常规遍历法:需要遍历一次罗马数字字符串,时间复杂度为 O ( n ) O(n) O(n),其中 n n n 是字符串的长度。
  • 逆序遍历法:同样需要遍历一次字符串,时间复杂度也是 O ( n ) O(n) O(n)

空间复杂度

  • 常规遍历法:使用了一个 HashMap 来存储罗马字符和整数值的映射,空间复杂度为 O ( 1 ) O(1) O(1),因为罗马字符的种类是固定的(只有 7 种)。
  • 逆序遍历法:也使用了一个 HashMap 存储映射,空间复杂度同样为 O ( 1 ) O(1) O(1)

四、总结

“罗马数字转整数”这道简单题虽然规则上有特殊情况,但通过合理的算法设计可以轻松解决。常规遍历法和逆序遍历法都能有效地将罗马数字转换为整数,它们的时间复杂度和空间复杂度基本相同。常规遍历法是正向处理字符串,需要对特殊情况进行额外的判断和索引移动;逆序遍历法则是逆向处理,通过比较相邻字符的数值来处理特殊情况,代码相对简洁。在实际应用中,可以根据个人的编程习惯选择合适的方法。希望通过这篇博客,大家能对罗马数字的转换有更深入的理解,同时掌握不同的解题思路和技巧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值