Medium
题目描述
七个不同的符号代表罗马数字,对应的值如下:
| 符号 | 数值 |
|---|---|
| I | 1 |
| V | 5 |
| X | 10 |
| L | 50 |
| C | 100 |
| D | 500 |
| M | 1000 |
罗马数字是通过从高位到低位附加十进制位值的转换来形成的。将十进制位值转换为罗马数字有以下规则:
- 如果数值不是以 4 或 9 开头,选择可以从输入中减去的最大值的符号,将该符号附加到结果中,减去其值,并将余数转换为罗马数字。
- 如果数值以 4 或 9 开头,使用减法形式,表示从后面的符号中减去一个符号,例如,4 是比 5 (V) 少 1 (I):IV,9 是比 10 (X) 少 1 (I):IX。只使用以下减法形式:4 (IV)、9 (IX)、40 (XL)、90 (XC)、400 (CD) 和 900 (CM)。
- 只有 10 的幂次(I、X、C、M)可以连续附加最多 3 次来表示 10 的倍数。你不能多次附加 5 (V)、50 (L) 或 500 (D)。如果你需要附加一个符号 4 次,使用减法形式。
给定一个整数,将其转换为罗马数字。
示例 1:
输入:num = 3749
输出:"MMMDCCXLIX"
解释:
3000 = MMM 即 1000 (M) + 1000 (M) + 1000 (M)
700 = DCC 即 500 (D) + 100 (C) + 100 (C)
40 = XL 即 50 (L) 减去 10 (X)
9 = IX 即 10 (X) 减去 1 (I)
示例 2:
输入:num = 58
输出:"LVIII"
解释:
50 = L
8 = VIII
示例 3:
输入:num = 1994
输出:"MCMXCIV"
解释:
1000 = M
900 = CM
90 = XC
4 = IV
约束条件:
- 1 <= num <= 3999
解题思路
解题思路
这道题的关键是理解罗马数字的构成规律。我们需要从最大的数值开始,逐步构建罗马数字字符串。
核心思路:
贪心策略:从大到小遍历所有可能的罗马数字组合(包括减法形式),每次选择不超过当前数值的最大组合。
预处理映射表:创建一个包含所有可能数值和对应罗马数字的映射表,包括特殊的减法形式(4, 9, 40, 90, 400, 900)。
构建过程:
- 从最大值开始遍历映射表
- 如果当前数值大于等于映射表中的值,就添加对应的罗马数字符号
- 从数值中减去对应的值,继续处理剩余部分
- 重复直到数值变为 0
算法步骤:
- 创建数值和罗马数字的对应数组,按降序排列
- 从最大值开始,计算当前数值可以包含多少个该罗马数字
- 将对应数量的罗马数字符号添加到结果中
- 更新剩余数值,继续处理下一个较小的罗马数字
这种方法的优势是代码简洁,逻辑清晰,时间复杂度为 O(1),因为最多只需要遍历 13 个固定的数值。
代码实现
class Solution {
public:
string intToRoman(int num) {
vector<int> values = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
vector<string> romans = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
string result = "";
for (int i = 0; i < values.size(); i++) {
while (num >= values[i]) {
result += romans[i];
num -= values[i];
}
}
return result;
}
};
class Solution:
def intToRoman(self, num: int) -> str:
values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
romans = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
result = ""
for i in range(len(values)):
while num >= values[i]:
result += romans[i]
num -= values[i]
return result
public class Solution {
public string IntToRoman(int num) {
int[] values = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
string[] romans = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
StringBuilder result = new StringBuilder();
for (int i = 0; i < values.Length; i++) {
while (num >= values[i]) {
result.Append(romans[i]);
num -= values[i];
}
}
return result.ToString();
}
}
var intToRoman = function(num) {
const values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
const romans = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"];
let result = "";
for (let i = 0; i < values.length; i++) {
while (num >= values[i]) {
result += romans[i];
num -= values[i];
}
}
return result;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(1) | 最多遍历 13 个固定的罗马数字组合,每个数字最多重复 3-4 次 |
| 空间复杂度 | O(1) | 使用固定大小的数组存储映射关系,额外空间为常数级别 |
相关题目
. Roman to Integer (Easy)
. Integer to English Words (Hard)