zoukankan      html  css  js  c++  java
  • 【LeetCode】Roman to Integer & Integer to Roman

    Roman to Integer

    Given a roman numeral, convert it to an integer.

    Input is guaranteed to be within the range from 1 to 3999.


    首先学习一下罗马数字的规则:

    羅馬數字共有7個,即I(1)、V(5)、X(10)、L(50)、C(100)、D(500)和M(1000)。按照下述的規則可以表示任意正整數。需要注意的是罗马数字中没有“0”,與進位制無關。一般認為羅馬數字只用來記數,而不作演算。

    • 重複數次:一個羅馬數字重複幾次,就表示這個數的幾倍。
    • 右加左減:
      • 在較大的羅馬數字的右邊記上較小的羅馬數字,表示大數字加小數字。
      • 在較大的羅馬數字的左邊記上較小的羅馬數字,表示大數字减小數字。
      • 左减的数字有限制,仅限于I、X、C。比如45不可以写成VL,只能是XLV
      • 但是,左減時不可跨越一個位數。比如,99不可以用IC (100 - 1) 表示,而是用XCIX( (100 - 10) + (10 - 1) )表示。(等同於阿拉伯數字每位數字分別表示。)
      • 左減數字必須為一位,比如8寫成VIII,而非IIX。
      • 右加數字不可連續超過三位,比如14寫成XIV,而非XIIII。(見下方“數碼限制”一項。)
    • 加線乘千:
      • 在羅馬數字的上方加上一條橫線或者加上下標的Ⅿ,表示將這個數乘以1000,即是原數的1000倍。
      • 同理,如果上方有兩條橫線,即是原數的1000000(1000^2)倍。
    • 數碼限制:
      • 同一數碼最多只能出現三次,如40不可表示為XXXX,而要表示為XL。
      • 例外:由於IV是古羅馬神話主神朱庇特(即IVPITER,古羅馬字母裡沒有J和U)的首字,因此有時用IIII代替Ⅳ。

    这其中有一个很有意思的问题:

    对于这道题,真正有用的规则只有前面所述黑体的部分,那我们是“从前往后”扫描计算还是“从后往前”扫描呢?

    * 如果是从前往后,那么假定已经扫描过的位置都是已经处理了的(即这一位的值已经被计算过):

     1. 当 s[i] > s[i-1],应该是 s[i] - s[i-1],但是此时 s[i-1] 已经被处理并且一定是被加进了 ans (对 s[i-2] 分情况讨论便知),所以此时需要 ans += s[i] - 2*s[i-1];

     2. 当 s[i] <= s[i-1],应该是 加上 s[i-1],这没什么问题。

    * 如果是从后往前,那么假定已经扫描过的位置都是已经处理了的(即这一位的值已经被计算过):

     1. 当 s[i] >= s[i+1],把 s[i] 加进去即可( s[i+1] 是加进 ans 还是 减进 ans 的都没有影响),样例有 XCIX(99);

     2. 当 s[i] < s[i+1], 把 s[i] 减进 ans 即可。

    所以,相比之下“从后往前”的策略是更规范和统一,逻辑上也更清晰,ans 在处理过程中的波动理论上也更小,而且符合我们的假定:即只处理还未扫描到的位,已经扫描到的不再做任何 “补救” 形态的处理。

    下面,把两种策略的代码都贴出来:

    “从前往后”的策略:

     1 class Solution:
     2     # @param {string} s
     3     # @return {integer}
     4     def romanToInt(self, s):
     5         roman = {
     6             "I":    1,
     7             "V":    5,
     8             "X":    10,
     9             "L":    50,
    10             "C":    100,
    11             "D":    500,
    12             "M":    1000
    13             }
    14         ans = roman[s[0]]
    15         for i in range(1, len(s)):
    16             if roman[s[i]] > roman[s[i-1]]:
    17                 ans += roman[s[i]] - 2*roman[s[i-1]]
    18             else:
    19                 ans += roman[s[i]]
    20         return ans

    “从后往前”的策略:

     1 class Solution:
     2     # @param {string} s
     3     # @return {integer}
     4     def romanToInt(self, s):
     5         roman = {
     6             "I":    1,
     7             "V":    5,
     8             "X":    10,
     9             "L":    50,
    10             "C":    100,
    11             "D":    500,
    12             "M":    1000
    13             }
    14         n = len(s)
    15         ans = roman[s[n-1]]
    16         i = n-2
    17         while i >= 0:
    18             if roman[s[i]] >= roman[s[i+1]]:
    19                 ans += roman[s[i]]
    20             else:
    21                 ans -= roman[s[i]]
    22             i -= 1
    23         return ans

    Reference:

    http://blog.csdn.net/jellyyin/article/details/13165731


    Integer to Roman

    Given an integer, convert it to a roman numeral.

    Input is guaranteed to be within the range from 1 to 3999.

    Solution:

    反过来的关键在于找出能表示所有的数的“基本元”的集合,然后从数值大到小排列,依次从num里面减去,同时构造出罗马数字串,直至num为0。

    那么哪些是我们要找的“基本元”呢?

    让我们从小数字来看,首先 1 是已经存在的基本元(I),2和3则可以用 I 的重复来表示,但是 4 却已经不能用更 4 个 I 来表示了(受 “右加數字不可連續超過三位” 规则限制),而只能用 5-1 也就是 IV 来表示了。

    至此,6 - 8 也可以用 V 和 I 的组合表示了,但是对于 9,首先不能是 VIIII,5+4(VIV)也不行( I 位的符号受“右加左减”限制存在矛盾),而只能是 10 - 1 (IX)。

    至此,个位数的情况已经穷尽,而更高数量级的数字与此同理可以找出“基本元”,较小数量级的数又可以由已经找出的“基本元”的合法组合来表示,这就好比我们熟知的人民币数值系统。

    代码如下:

     1 class Solution:
     2     # @param {integer} num
     3     # @return {string}
     4     def intToRoman(self, num):
     5         values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
     6         numerals = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
     7         ans, i = "", 0
     8         while num:
     9             ans += (num//values[i]) * numerals[i]
    10             num %= values[i]
    11             i += 1
    12         return ans
  • 相关阅读:
    java 多级图的最短路径
    在dos中编译java文件
    apollo客户端的长轮询机制的原理
    Apollo配置中心动态生效实现原理
    jmx_exporter+prometheus+grafana实现kafka metric监控
    XXL-JOB(1) 分布式任务系统选型和XXL-JOB介绍,这篇文章相当的经典呀
    grafana根据不同prometheus server统计数据
    XXL-JOB的使用教程
    普罗米修斯官方文档
    Prometheus标签的管理
  • 原文地址:https://www.cnblogs.com/maples7/p/4732762.html
Copyright © 2011-2022 走看看