天天看点

LeetCode算法个人解答——13.罗马数字转整数题目解1(执行时间200ms,暴力解法)解2(最佳解,124ms)

题目

罗马数字包含以下七种字符: 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.
           

解1(执行时间200ms,暴力解法)

解题思路

1.字符串中,count可以计算某个字符出现的次数
2.无视特殊规则的情况下,取得数值的大小num1
3.计算特殊规则字符出现的次数
4.特殊规则字符出现时,找到规律:
		IV 和 IX 只比 V 和 X 小 1
  其他同理
5.计算得到结果:num = num1 - num2*2
注:特殊规则包含==两个字符==,所以需要减取两次才能保证特殊规则的字符的值
           
class Solution:
    def romanToInt(self, s):
        """
        :type s: str
        :rtype: int
        """
        # 计算字符串中分别有多少 I, V, X, L, C, D, M
        num_I = s.count('I')*1
        num_V = s.count('V')*5
        num_X = s.count('X')*10
        num_L = s.count('L')*50
        num_C = s.count('C')*100
        num_D = s.count('D')*500
        num_M = s.count('M')*1000
        # 按数值计算大小
        num1 = num_I + num_V + num_X + num_L + num_C + num_D + num_M
        # 计算字符串中分别有多少 IV, IX, XL, XC, CD, CM
        num_I2 = (s.count('IV') + s.count('IX'))*1
        num_X2 = (s.count('XL') + s.count('XC'))*10
        num_C2 = (s.count('CD') + s.count('CM'))*100
        # 按数值计算大小
        num2 = num_I2 + num_X2 + num_C2
        # 两个数值相减
        num = num1 - num2*2
        return num
           

解2(最佳解,124ms)

解题思路

1.通过观察,可以发现罗马数字从后往前读,是按照数值大小来排序的
2.当出现特殊规则时,数值小的会出现在数值大的数字的另一边
3.通过这个特性可以判断是否出现特殊规则
4.出现特殊规则时,数值大的减去数值小的就是特殊规则的对应数值
           
class Solution:
    def romanToInt(self, s):
        """
        :type s: str
        :rtype: int
        """
                # 创建字典,将各个罗马数字和对应的数值存入字典中
        roman = {'M': 1000, 'D': 500, 'C': 100, 'L': 50, 'X': 10, 'V': 5, 'I': 1}
        # 创建变量,用于存储上一个罗马数字的数值
        carry = 0
        # 创建变量,用于存储结果
        res = 0
        # 反方向遍历罗马数字
        for letter in s[::-1]:
            # 从字典取得对应罗马数字的数值
            cur = roman[letter]
            # 判断数值是否大于或等于前一个罗马数字的数值
            if cur >= carry:
                # 原本res的基础上加上数值
                res += cur
            # 数值小于前一个罗马数字的数值
            else:
                # 原本res的基础上减取数值(特殊规则固定,所以不需要考虑太多)
                res -= cur
            # 取较大值的数值(针对特殊规则)
            carry = max(cur, carry)
        return res