基于贪心算法解决,十分简洁。
题目
罗马数字包含以下七种字符: 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 到 3999 的范围内。
示例
示例 1:
示例 2: 示例 3: 示例 4: 解释: L = 50, V = 5, III = 3.
示例 5: 解释: M = 1000, CM = 900, XC = 90, IV = 4.
示例 6:
考察知识点
条件判定、贪心算法
核心思想
限制条件有限
所以设置好判定条件就能实现该算法。
使用贪心算法实现
贪心算法(又称贪婪算法)是指,在对 问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部 最优解。 贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
假设一个问题比较复杂,暂时找不到全局最优解,那么我们可以考虑把原问题拆成几个小问题(分而治之思想),分别求每个小问题的最优解,再把这些“局部最优解”叠起来,就“当作”整个问题的最优解了。
“将整数转换为罗马数字”的过程,就是用上面这张表中右边的数字作为“加法因子”去分解一个整数,目的是“分解的整数个数”尽可能少,因此,对于这道问题,类似于用最少的纸币凑成一个整数,贪心算法的规则如下:
每一步都使用当前较大的罗马数字作为加法因子,最后得到罗马数字表示就是长度最少的。
LeetCode题解
Python版本
自己实现的一个基于条件判定的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 class Solution : def intToRoman (self, num: int ) -> str: special_pairs = { 4 : "IV" , 9 : "IX" , 40 : "XL" , 90 : "XC" , 400 : "CD" , 900 : "CM" } normal_pairs = { 1 : "I" , 5 : "V" , 10 : "X" , 50 : "L" , 100 : "C" , 500 : "D" , 1000 : "M" } result = [] count = 0 while num != 0 : remainder = (num % 10 ) * (10 ** count) count += 1 num //= 10 if remainder in special_pairs: tmp_str = special_pairs[remainder] result.append(tmp_str) elif remainder in normal_pairs: tmp_str = normal_pairs[remainder] result.append(tmp_str) elif count == 1 : if remainder <= 3 : tmp_str = remainder * normal_pairs[1 ] else : tmp_str = normal_pairs[5 ] + (remainder-5 ) * normal_pairs[1 ] result.append(tmp_str) elif count == 2 : remainder //= 10 if remainder <= 3 : tmp_str = remainder * normal_pairs[10 ] else : tmp_str = normal_pairs[50 ] + (remainder-5 ) * normal_pairs[10 ] result.append(tmp_str) elif count == 3 : remainder //= 100 if remainder <= 3 : tmp_str = remainder * normal_pairs[100 ] else : tmp_str = normal_pairs[500 ] + (remainder-5 ) * normal_pairs[100 ] result.append(tmp_str) elif count == 4 : remainder //= 1000 tmp_str = remainder * normal_pairs[1000 ] result.append(tmp_str) else : print("有问题" ) tmp_str = "" for i in range (len (result)-1 , -1 , -1 ): tmp_str += result[i] return tmp_str
时间复杂度 \(O(n)\) 遍历了一遍输入数字 遍历了一遍转化结果
贪心算法版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution (object ): def intToRoman (self, num: int ) -> str: nums = [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" ] index = 0 res = '' while index < 13 : while num >= nums[index]: res += romans[index] num -= nums[index] index += 1 return res
时间复杂度:\(O(1)\) ,虽然看起来是两层循环,但是外层循环的次数最多 12,内层循环的此时其实也是有限次的,综合一下,时间复杂度是 \(O(1)\) 。
空间复杂度:\(O(1)\) ,这里使用了两个辅助数字,空间都为 13,还有常数个变量,故空间复杂度是 \(O(1)\) 。
有效语法糖
1、Python中的从后往前输出
>>> a [3 , 2 , 1 ]>>> for i in range (len (a)-1 , -1 , -1 ): print(a[i]) 1 2 3