在罗马数字系统中,七个不同的符号代表不同的值:
符号 | 值 |
---|---|
I | 1 |
V | 5 |
X | 10 |
L | 50 |
C | 100 |
D | 500 |
M | 1000 |
罗马数字的表示方式是从最大值开始逐次减去每个符号的值,通过组合这些符号构建最终的表示形式。本文将介绍一个基于贪心策略的解决方案,将整数转换为罗马数字。
解题思路
给定一个整数,我们需要通过罗马数字表示出来。罗马数字的构建规则非常有趣:通常情况下,从较大的数值符号开始,按递减顺序逐步添加符号来表示出整个数。但当数位中以4或9开头时,采用“减法形式”表示——比如4用“IV”而不是“IIII”表示,9则用“IX”而不是“VIIII”。这里,我们需要从高位逐步匹配适合的罗马符号值,并从当前整数中减去该符号对应的数值,直到当前整数变为0。
在此代码实现中,首先定义了一个映射表,按从大到小的顺序列出整数与罗马符号的关系,这样便于直接找到合适的符号。然后,我们从最大的数值符号开始遍历,使用一个 while
循环来处理当前数值。当当前数值大于等于符号所代表的值时,减去该值并将对应的符号附加到结果字符串中。通过不断重复上述过程,我们最终得到完整的罗马数字表示。
示例
以下是几个示例解释:
- 输入
num = 3749
,输出结果为"MMMDCCXLIX"
,解释如下:- 3000 = “MMM”,因为 1000 (M) + 1000 (M) + 1000 (M)
- 700 = “DCC”,因为 500 (D) + 100 © + 100 ©
- 40 = “XL”,因为 50 (L) - 10 (X)
- 9 = “IX”,因为 10 (X) - 1 (I)
- 输入
num = 58
,输出结果为"LVIII"
,解释如下:- 50 = “L”
- 8 = “VIII”,因为 5 (V) + 1 (I) + 1 (I) + 1 (I)
- 输入
num = 1994
,输出结果为"MCMXCIV"
,解释如下:- 1000 = “M”
- 900 = “CM”,因为 1000 (M) - 100 ©
- 90 = “XC”,因为 100 © - 10 (X)
- 4 = “IV”,因为 5 (V) - 1 (I)
代码实现
class Solution {
public:string intToRoman(int num) {string ans;vector<pair<int, string>> m = {{1000, "M"},{900, "CM"},{500, "D"},{400, "CD"},{100, "C"},{90, "XC"},{50, "L"},{40, "XL"},{10, "X"},{9, "IX"},{5, "V"},{4, "IV"},{1, "I"}};for(auto p : m) {while(num >= p.first) {num -= p.first;ans += p.second;}}return ans;}
};
代码解释
- 定义罗马数字映射表:首先,我们使用
vector<pair<int, string>>
来存储每一个可能的数值和相应的罗马字符。这里按数值大小从高到低排序,便于逐步匹配。 - 贪心算法构建字符串:接下来,遍历映射表中的每个
(值, 符号)
对。当输入整数大于等于当前值时,循环执行减去当前值并将相应符号添加到结果字符串。通过这个贪心算法,我们逐步构建最终的罗马数字表示。 - 终止条件:当输入整数逐步被减为0时,算法终止,最终字符串即为罗马数字。
时间复杂度与空间复杂度
时间复杂度:O(1)。虽然存在一个 while
循环嵌套在 for
循环中,但我们处理的是有限数的整数符号对,映射表长度固定。故时间复杂度可以认为是常数时间。
空间复杂度:O(1)。代码只需要常量空间存储罗马数字符号对,以及一个字符串变量用于保存结果,因此空间复杂度为常数。
扩展思路
在不同的语言中实现该方法也相对容易。例如,在 Python 中可以使用类似的方法,也可以采用字典和字符串的拼接来表示相应的转换。需要注意的是,罗马数字规则虽然固定,但在一些特殊情况下仍需仔细考虑,比如在多层循环处理时可能会影响效率。贪心算法适用于此类问题,因为它确保每次选择的是当前情况下最佳的罗马符号。
总结
该解法基于贪心算法思想,通过逐步减去数值并附加罗马符号的方式实现整数到罗马数字的转换。代码清晰、易于理解,且高效处理所有可能的输入整数。总体上,这种方法不仅具有简单的逻辑流,也符合罗马数字的规则,尤其是减法表示法的运用。