力扣题库13,罗马数字转整数。
题目链接点这里。
罗马数字包含以下七种字符: 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:
输入: “III” 输出: 3 示例 2:
输入: “IV” 输出: 4 示例 3:
输入: “IX” 输出: 9 示例 4:
输入: “LVIII” 输出: 58 解释: L = 50, V= 5, III = 3. 示例 5:
输入: “MCMXCIV” 输出: 1994 解释: M = 1000, CM = 900, XC = 90, IV = 4.
提示:
题目所给测试用例皆符合罗马数字书写规则,不会出现跨位等情况。 IC 和 IM 这样的例子并不符合题目要求,49 应该写作 XLIX,999 应该写作 CMXCIX 。 关于罗马数字的详尽书写规则,可以参考罗马数字 - Mathematics 。
做了这道题我才知道原来罗马数字就是简单的将数字放在一起,不像阿拉伯数字不同的位数会代表不同的倍数。所以其实思路也很简单,类似于队列,每出来一个值就查询一下字典对应的结果然后进行累加就可以了。只是需要注意几个特例,在处理当前元素的时候还需要考虑下一个元素。
这里直接将所有的可能性都放进了字典里面,对字符串遍历了一边,时间复杂度O(N)。执行用时: 68 ms,击败了35%的提交。
网上还有个思路让我眼前一亮,就是结合罗马数字的特性,从高位到低位的字母代表的数字应该是递减的。假如出现了一个增加就说明有事情,出现了特殊情况。特殊情况下就相当于用后面一位减去前面一位。所以一旦遇到这种特殊情况就改一下符号就行,就省略了一个字典的查询。
class Solution: def romanToInt(self, s: str) -> int: temp=list(s) length = len(temp) items={'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000} result =0 i=0 while i < length: cur = items[temp[i]] if i == length-1: result+=cur return result else: nex = items[temp[i+1]] if cur < nex: result -= cur i+=1 else: result+=cur i+=1 return result思路虽然很新奇,但是执行用时: 68 ms,跟上面一样。
心有不甘,觉得是不是每次循环中进行了两次字典查询耗时太多,于是修改了下代码
class Solution: def romanToInt(self, s: str) -> int: li=list(s) length = len(li) items={'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000} result =0 temp=0 cur =0 for i in range(length): item = li[i] cur = items.get(item) if cur > temp: result -=temp else: result +=temp temp = cur result+=cur return result增加了一个临时变量来存储,结果执行用时: 84 ms。时间不减反增。
其实每种解法的时间复杂度都是O(N),很神奇。
网上有人用java的switch/case结构,只用了4秒就搞定了,但其实思路差不多。我很纳闷,难道hashmap的查询就比switch/case慢这么多吗,然后发现python没有switch/case结构。
我是T型人小付,一位坚持终身学习的互联网从业者。喜欢我的博客欢迎在csdn上关注我,如果有问题欢迎在底下的评论区交流,谢谢。