代码训练LeetCode(28)罗马数字

代码训练(28)LeetCode之罗马数字

Author: Once Day Date: 2025年6月10日

漫漫长路,才刚刚开始…

全系列文章可参考专栏: 十年代码训练_Once-Day的博客-优快云博客

参考文章:

1. 原题

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

字符          数值
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 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 <= 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 等。

罗马数字是由七种基本符号构成,每种符号对应一个基本的数值。通常情况下,小的数字放在大的数字右边,表示这些值的累加。然而,如果小的数字放在大的数字左边,则表示大的数减去小的数。这种特例仅限于几种特定的组合。

解题思路:

  1. 建立映射:首先,我们需要一个映射来存储每个罗马数字字符对应的整数值。
  2. 遍历字符串:对给定的罗马数字字符串进行遍历,比较当前字符代表的数值与下一个字符代表的数值。
  3. 加减逻辑处理:如果当前字符代表的数值小于其右边的字符代表的数值,说明这是一个特殊的组合,执行减法操作;否则,执行加法操作。
  4. 累加结果:将所有得到的结果累加,得到最终的整数值。

分析步骤:

假设输入的罗马数字为 “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. 总结

通过这个题目,我们可以学习到如何处理和转换不同的数值表示法。此外,有效使用数据结构(如数组)来优化查找和访问操作,对于提升编程效率和性能有着重要的作用。对于进一步提升编程能力,应当注重算法效率的同时,也要注意代码的可读性和维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值