每日算法 -【Swift 算法】将整数转换为罗马数字
💡 Swift:将整数转换为罗马数字(含思路讲解与详细注释)
罗马数字是一种古老的数字表示方式,虽然在现代我们不再使用它进行计算,但在表盘、章节、纪念碑等地方依然很常见。今天我们就来实现一个经典算法题:将整数转换为罗马数字,并用 Swift 编写完整代码及思路解析。
🏛 罗马数字基本知识
罗马数字使用以下七个符号表示数字:
符号 | 值 |
---|---|
I | 1 |
V | 5 |
X | 10 |
L | 50 |
C | 100 |
D | 500 |
M | 1000 |
此外,还需要掌握减法规则:
当数字以 4
或 9
结尾时,不能用重复表示法,比如:
- 4 应该写作
IV
(5 - 1) - 9 应该写作
IX
(10 - 1) - 40 应该写作
XL
(50 - 10) - 90 应该写作
XC
- 400 应该写作
CD
- 900 应该写作
CM
这些特殊组合是算法的关键。
🎯 解题思路(贪心算法)
我们采用贪心算法的策略来处理:
- 准备一个有序数组(从大到小)保存所有罗马数字的值和对应符号。
- 遍历数组,每次从剩余的
num
中尽量减去最大的值,并把对应的符号拼接到结果字符串中。 - 重复步骤直到
num == 0
。
✅ Swift 实现(含详细注释)
func intToRoman(_ num: Int) -> String {// 从大到小排列的数值-符号对,包括减法形式(如 IV、CM 等)let valueSymbolPairs: [(Int, String)] = [(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")]var num = num // 输入整数var result = "" // 存放最终结果// 遍历所有的数值-符号对for (value, symbol) in valueSymbolPairs {// 每次尽可能多减去当前 valuewhile num >= value {result += symbol // 拼接对应的罗马数字num -= value // 减去对应的值}}return result
}
🧪 示例输入输出
print(intToRoman(3)) // 输出: "III"
print(intToRoman(58)) // 输出: "LVIII"
print(intToRoman(1994)) // 输出: "MCMXCIV"
⚙️ 时间和空间复杂度分析
-
时间复杂度:O(1)
输入整数范围是固定(通常为 1~3999),最多遍历 13 个符号,操作次数是常数级别。 -
空间复杂度:O(1)
只使用常量数组和一个可变字符串,无额外空间开销。
🧠 延伸思考:如何将罗马数字转换为整数?
这是这道题的逆问题,也非常经典。下面是详细的解法与注释。
我们要根据罗马数字字符串(例如 "MCMXCIV"
)逐字符解析出它的整数值。核心逻辑是:
- 如果当前字符对应的值 小于 下一个字符,说明这是一种减法组合(如
IV
,XC
,CM
)。 - 否则就是普通加法。
Swift 示例代码(含详细备注)
func romanToInt(_ s: String) -> Int {// 罗马字符对应的整数映射表let romanMap: [Character: Int] = ["I": 1, "V": 5, "X": 10,"L": 50, "C": 100,"D": 500, "M": 1000]let chars = Array(s) // 将字符串转换为字符数组,便于索引访问var total = 0 // 最终结果var i = 0 // 当前遍历的位置while i < chars.count {let currentVal = romanMap[chars[i]]! // 当前字符的数值// 判断是否存在下一个字符,并比较其值if i + 1 < chars.count, let nextVal = romanMap[chars[i + 1]], currentVal < nextVal {// 如果当前值小于下一个值,说明是减法组合(如 IV = 5 - 1)total += (nextVal - currentVal)i += 2 // 跳过这两个字符} else {// 普通加法情况(如 VI = 5 + 1)total += currentVali += 1}}return total
}
示例验证
print(romanToInt("III")) // 输出: 3
print(romanToInt("LVIII")) // 输出: 58
print(romanToInt("MCMXCIV")) // 输出: 1994
🏁 总结
- 本题的核心是贪心策略:总是选用当前能减去的最大数值的罗马符号。
- 处理好减法组合(如 IV、IX 等)是关键。
- Swift 实现简洁高效,时间和空间复杂度都为常数级。
- 进一步的练习是:实现罗马数字转整数,掌握双向处理。
如果你觉得这篇文章对你有帮助,不妨分享给你的 Swift 同学一起学习吧。也欢迎留言交流更多有趣的算法题目!