zoukankan      html  css  js  c++  java
  • 罗马数字转整数的算法

    罗马数字转整数功能的实现

    题目

    # 罗马数字包含以下七种字符: 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。 IV=4 IX=9
    # X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。 XL=40 XC=90
    # C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。CD=400 CM=900
    # 给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。
    #
    # 来源:力扣(LeetCode)
    # 链接:https://leetcode-cn.com/problems/roman-to-integer
    # 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    

    思路

    拿到这道题时,我首先想的是建立一个roman数列,里面从小到大保存着所有的罗马字符,同时建立一个字典从小到大保存着罗马字符以及其对应的数量大小。如下所示:

    roman = ['I', 'V', 'X', 'L', 'C', 'D', 'M']
    roman_value = {'I': 1,
                   'V': 5,
                   'X': 10,
                   'L': 50,
                   'C': 100,
                   'D': 500,
                   'M': 1000
                   }
    

    解题思路则是,将拿到的罗马数字用for循环取值,一次取两个。若是取到的第一个字符比第二个字符小,则加上第二个字符代表的值减去第一个字符代表的值(如IX=10-1=9),否则加上第二个数字的值。然后再判断第二个字符和第三个字符......

    实现算法

    出错算法

    首次解题时,我写出了如下算法:

    def romanToInt(s):
        res = 0
        for i in s:  # i:第一个数
            if s.index(i) != len(s) + 1:
                j = s[s.index(i) + 1] #出错 由于X出现了两次,当取i='X'时,index(i)会默认取第一个'X'的索引
                if roman_value[i] < roman_value[j]: 
                    res += roman_value[j] - roman_value[i]
                    res -= roman_value[j]
                    # 由于第二次循环还是会循环到j,相当于再加了一次j,所以直接先减去以抵消
                else:
                    res += roman_value[i]
            else:
                res += roman_value[i]
        return res
    
    
    
    

    在转换‘MXCIX’,也就是罗马字符的1099时,输出的答案为1079。然后我debug出了一个我无法解决bug。

    我使用了.index的方法,也就是根据每次循环取到的具体字符 i 来反推这个字符在原字符串 s 中的索引,并且根据这个索引+1的值来取到下一个值.但是我在使用这种方法的时候没有考虑到字符可能重复出现的情况.就比如在转换‘MXCIX’时,当 i 取到第二个X(高亮X)时, s.index(i)任然是第一个X的索引,导致程序出错.

    这个bug以我现在的知识无法解决,于是我在查阅一些资料后写出了改进算法:

    改进算法

    def romanToInt(s):
        res = 0
        for i,v in enumerate(s):  # i:索引 v:值
            if i != len(s)-1:
                j = s[i + 1]   #j: s中以i+1为索引的值
                if roman_value[v] < roman_value[j]:
                    res += roman_value[j] - roman_value[v]
                    res -= roman_value[j]
                else:
                    res += roman_value[v]
            else:
                res += roman_value[v]
        return res
    

    主要改进是使用了enumerate(枚举)这个方法,它的作用是分别返回索引以及值.这样就在循环的一开始确定了索引和值,而不是通过值反推索引,这样会因为重复出现的值出bug.

    反思:enumerate真好真好用啊

  • 相关阅读:
    dN/dS与分子进化常用软件
    samtools和bcftools使用说明
    变异检测VarScan软件使用说明
    线程可以共享进程里的哪些资源
    函数调用与系统调用的区别
    海量数据统计出现次数
    海量数据查找问题
    建立高并发模型需要考虑的点
    言简意赅的TIME_WAIT
    常用的TCP选项
  • 原文地址:https://www.cnblogs.com/Sheppard/p/11264544.html
Copyright © 2011-2022 走看看