力扣12&13-整数与罗马数字互换

简介: 力扣12&13-整数与罗马数字互换

力扣12-整数转罗马数字

原题链接:https://leetcode.cn/problems/integer-to-roman/

题目描述

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

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

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

输入: num = 3

输出: “III”

示例 2:

输入: num = 4

输出: “IV”

示例 3:

输入: num = 9

输出: “IX”

示例 4:

输入: num = 58

输出: “LVIII”

解释: L = 50, V = 5, III = 3.

示例 5:

输入: num = 1994

输出: “MCMXCIV”

解释: M = 1000, CM = 900, XC = 90, IV = 4.

提示:

  • 1 <= num <= 3999

解题

首先要明白有多少种的罗马数字符号,除了 I, V, X, L,C,D 和 M,还有5-110-150-10100-10等情况,一共是十三种

"I","IV","V","IX","X","XL","L","XC","C","CD","D","CM","M"

分别对应的数值为:

1,4,5,9,10,40,50,90,100,400,500,900,1000

我们要做的,就是从最大值,也就是最右端开始,对比原整数,如果原整数大于该值,则创建字符串并追加对应的罗马数字,举个例子:

  1. 整数是21
  2. 对比最右端M对应的1000,21小于1000,换成CM对应的900,继续对比
  3. 以此类推,直到移动到罗马数字X时,21>10,所以结果字符串目前修改为X,整数修改为11
  4. 继续判断X,结果字符串修改为XX,整数修改为1
  5. 继续移动到I,结果字符串修改为XXI,整数修改为0
  6. 结束循环,返回字符串XXI

需要注意的是:

  • 不是碰到小于自身的罗马数字就跳出循环,比如x=3时,需要替换三次I
  • 是从最大值到最小值检索
  • 需要使用const char*来接收罗马数字组成的数组
  • 结果字符串在声明时使用动态内存的方法申请空间,从const char*类型的字符串复制时需用strcpy函数
  • 或使用calloc申请空间,默认填充为0;

力扣给的难度是中等题,更麻烦的是如何化简代码,如果用很多if,会显得很臃肿。

我们可以将值存到数组中,使用下标访问。

敲代码

解题方法其实很多,上面只是其中一种

C语言的字符串操作比较麻烦,应注意使用strcat、strcpy、strncpy等字符串以及动态内存的相关方法

char* intToRoman(int num) {
    char* result = (char*)calloc(20,sizeof(char));
    int key[] = { 1,4,5,9,10,40,50,90,100,400,500,900,1000 };
    const char* value[] = {"I","IV","V","IX","X","XL","L","XC","C","CD","D","CM","M"};
    for (int i = sizeof(value) / sizeof(value[0])-1; i >=0 ; i--)
    {
        while (num >= key[i])
        {
            num -= key[i];
            strcat(result, value[i]);
        }
    }
    return result;
}

运行结果

执行用时:4 ms, 在所有 C 提交中击败了80.14%的用户

内存消耗:5.8 MB, 在所有 C 提交中击败了49.10%的用户

通过测试用例:3999 / 3999

力扣13-罗马数字转整数

原题链接:https://leetcode.cn/problems/roman-to-integer/

题目描述

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

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

例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做  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 = “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 <= s.length <= 15
  • s 仅含字符 (‘I’, ‘V’, ‘X’, ‘L’, ‘C’, ‘D’, ‘M’)
  • 题目数据保证 s 是一个有效的罗马数字,且表示整数在范围 [1, 3999] 内
  • 题目所给测试用例皆符合罗马数字书写规则,不会出现跨位等情况。
  • IL 和 IM 这样的例子并不符合题目要求,49 应该写作 XLIX,999 应该写作 CMXCIX 。

解题

在解完上一道整数转罗马数字的题目后,看到这个题,是否可以使用上一题的方法?设:

const char* key[] = { "I","IV","V","IX","X","XL","L","XC","C","CD","D","CM","M" };

int value[] = { 1,4,5,9,10,40,50,90,100,400,500,900,1000 };

我们循环检索字符串中是否有key值,有则修改结果整型,填充原字符串中的重复位置为无关字符。

那么,问题便出现了,key数组的最右侧是M。

假设现在有MMM和MCM两个罗马数字,第一个很明显会返回3000,但第二个字符串可能会返回2100,因为在检索M时无法避免混淆独立的M和CM中的M。

每次检索时都需要加额外的限制条件,因此,我们换一种方法。

对于罗马数字,如IV,如果左侧字母小于右侧,那么便是减去数值小的字母,反之则为加

对于最后一个字符,右侧没有与之对比的字符,并且也不可能是减,可以在循环外单独添加

由于每次对比需要两个下标,因此循环结束条件应是strlen(s)-2,避免最后一个字符对比时越界

比如:IVI

  • 首先,这个罗马数字是不存在的,可以直接写成V
  • 其次,用上面的方法,也能求出来5:I小于V,V大于I,最后一个字符为I,单独加入
  • 结果为-1+5+1=5

上代码

代码中value['I' - 'A']是为了压缩空间,能够根据字符快速的索引对应的数值

int romanToInt(char* s) {
    int result = 0;
    int value[26];
    value['I' - 'A'] = 1;
    value['V' - 'A'] = 5;
    value['X' - 'A'] = 10;
    value['L' - 'A'] = 50;
    value['C' - 'A'] = 100;
    value['D' - 'A'] = 500;
    value['M' - 'A'] = 1000;
    for (int i = 0; i < strlen(s) - 1; i++)
    {
        if (value[s[i] - 'A'] >= value[s[i + 1] - 'A'])
            result += value[s[i] - 'A'];
        else
            result -= value[s[i] - 'A'];
    }
    result += value[s[strlen(s) - 1] - 'A'];
    return result;
}

运行结果

执行用时:8 ms, 在所有 C 提交中击败了55.51%的用户

内存消耗:5.8 MB, 在所有 C 提交中击败了18.16%的用户

通过测试用例:3999 / 3999

总结

两个题目看起来很像,一个是字符串转整型,一个是整型转字符串,使用的方法不同。

回文数的时候,如果传入形式分别为字符串和整型,处理方法也不同。

C语言中字符串和内存操作比较麻烦,应该数量掌握常用的字符串和内存方法,以及还应注意const char*char*直接的类型转换问题。

目前我的方法就是,如果处理字符串,就逐字符操作,初始化、赋值、修改用动态内存和strncpy的方法(因为直接赋值是const char*,无法修改,需要从字符常量区搬到栈区或者堆区)

如果处理整型,比较容易,符合条件加减即可

目录
相关文章
|
1月前
|
存储
LeetCode整数反转
解决LeetCode上的整数反转问题的几种方法,包括错误的方法和优化后的解决方案,以及如何避免反转后的整数超出32位有符号整数范围的问题。
35 1
|
1月前
【LeetCode】整数翻转
【LeetCode】整数翻转
15 1
|
1月前
|
存储 C++
Leetcode第十二题(整数转罗马数字)
LeetCode第12题“整数转罗马数字”的解题方法,包括罗马数字的基本规则和特殊规则,以及如何使用C++实现整数到罗马数字的转换。
15 0
|
1月前
|
C++
Leetcode第十三题(罗马数字转整数)
这篇文章介绍了LeetCode第13题“罗马数字转整数”的解题方法,通过一个C++的类`Solution`中的`romanToInt`函数来实现,该函数使用哈希表和遍历字符串的方法,根据罗马数字的规则将输入的罗马数字字符串转换为对应的整数值。
48 0
|
1月前
|
算法 C++
Leetcode第八题(字符串转换整数(atoi))
这篇文章介绍了LeetCode上第8题“字符串转换整数(atoi)”的解题思路和C++的实现方法,包括处理前导空格、正负号、连续数字字符以及整数溢出的情况。
17 0
|
2月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
3月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
57 6
|
3月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
114 2
|
20天前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
16 1
|
2月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口