zoukankan      html  css  js  c++  java
  • LeetCode.12-整数转罗马数字符串(Integer to Roman)

    这是悦乐书的第351次更新,第376篇原创

    01 看题和准备

    今天介绍的是LeetCode算法题中Medium级别的第6题(顺位题号是12)。罗马数字由七个不同的符号表示:I,V,X,L,C,D和M.

    符号    值
    I       1
    V       5
    X       10
    L       50
    C       100
    D       500
    M       1000
    

    例如,2用罗马数字写成II,由两个I加在一起。12写为XII,简称为X + II
    27写成XXVII,即XX + V + II

    罗马数字通常从左到右从最大到最小。但是,四个数字不是IIII。相反,4写为IV
    因为IV之前,我们做减法得到4。同样的原则适用于9,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的范围内。例如:

    输入:3
    输出:“III”

    输入:4
    输出:“IV”

    输入:9
    输出:“IX”

    输入:58
    输出:“LVIII”
    说明:L = 50,V = 5,III = 3。

    输入:1994
    输出:“MCMXCIV”
    说明:M = 1000,CM = 900,XC = 90,IV = 4。

    02 第一种解法

    题目要求我们将整数转成罗马数字符串来表示,和之前遇到的罗马数字符串转整数正好相反。

    题目限定了num的范围,[1,3999],针对常见的数字,列了下面这些罗马数和整数的对应关系:

               900  CM    90  XC    9  IX
    
               800  DCCC  80  LXXX  8  VIII 
               700  DCC   70  LXX   7  VII
               600  DC    60  LX    6  VI
               500  D     50  L     5  V
    
               400  CD    40  XL    4  IV
    
    3000  MMM  300  CCC   30  XXX   3  III
    2000  MM   200  CC    20  XX    2  II
    1000  M    100  C     10  X     1  I
    

    我们可以将他们的对应关系分为4组:

    • 第一组,最高位小于4,他们对应的罗马数是叠加的,例如1000是M,3000是MMM

    • 第二组,最高位等于4,他们对应的罗马数是在以5开头罗马数前加上以1开头的罗马数,且两者是相邻的关系。

    • 第三组,最高位在5到8之间,对应的罗马数是以5开头的罗马数为基础,后跟上叠加的1开头的罗马数,两者也是相邻的关系。

    • 第四组,最高为等于9,对应的罗马数是以1开头的罗马数间隔组合,例如900,在代表1000的M前加代表100的C,即CM,两者中间间隔一位。

    根据以上的对应关系组合,我们将不同整数、罗马数字符串初始化为数组,由高位到低位,依次计算罗马数。

    public String intToRoman(int num) {
        String[] roman = {"M", "D", "C", "L", "X", "V", "I"};
        int[] value = {1000, 500, 100, 50, 10, 5, 1};
        StringBuilder sb = new StringBuilder();
        for (int i=0; i<value.length; i+=2) {
            // 得到当前num的最高位
            int tem = num/value[i];
            if (tem < 4) {
                // 叠加
                for (int j=0; j<tem; j++) {
                    sb.append(roman[i]);
                }
            } else if (tem == 4) {
                // 相邻
                sb.append(roman[i]+roman[i-1]);
            } else if (tem > 4 && tem < 9) {
                // 相邻
                sb.append(roman[i-1]);
                for (int j=6; j<=tem; j++) {
                    sb.append(roman[i]);
                }
            } else if (tem == 9) {
                // 间隔两位
                sb.append(roman[i]+roman[i-2]);
            }
            // 去掉已经参与计算的高位
            num = num%value[i];
        }
        return sb.toString();
    }
    

    03 第二种解法

    在第一种解法的基础上,我们将初始数组中的元素分别对应增加了6位,以9和4开头。依旧是从高位往低位计算,与第一种解法中利用取余、取整不同,此解法是循环做减法,直到num剩下的值小于当前需要减去的值,才会寻找下一个需要减去的数。

    public String intToRoman2(int num) {
        String[] roman = {"M", "CM", "D", "CD", "C", "XC",
                "L", "XL", "X", "IX", "V", "IV", "I"};
        int[] value = {1000, 900, 500, 400, 100, 90,
                50, 40, 10, 9, 5, 4, 1};
        StringBuilder sb = new StringBuilder();
        for (int i=0; i<value.length; i++) {
            while (num >= value[i]) {
                sb.append(roman[i]);
                num -= value[i];
            }
        }
        return sb.toString();
    }
    

    04 第三种解法

    还有一种取巧的解法。因为题目限定num的范围,最高不会超过4000,我们可以把num拆成4个部分,千位只有四种可能,0(num是一个三位数)、1、2、3,百位对应的有10种可能,0到9,十位和个位也是10种可能,只需要将他们都列出来,依次取num中不同位对应的字符串即可。

    此解法的时间复杂度是O(1)

    public static String intToRoman3(int num) {
        String M[] = {"", "M", "MM", "MMM"};
        String C[] = {"", "C", "CC", "CCC", "CD", 
                "D", "DC", "DCC", "DCCC", "CM"};
        String X[] = {"", "X", "XX", "XXX", "XL", 
                "L", "LX", "LXX", "LXXX", "XC"};
        String I[] = {"", "I", "II", "III", "IV", 
                "V", "VI", "VII", "VIII", "IX"};
        return M[num/1000] + C[(num%1000)/100] + 
                X[(num%100)/10] + I[num%10];
    }
    

    05 小结

    算法专题目前已连续日更超过六个月,算法题文章219+篇,公众号对话框回复【数据结构与算法】、【算法】、【数据结构】中的任一关键词,获取系列文章合集。

    以上就是全部内容,如果大家有什么好的解法思路、建议或者其他问题,可以下方留言交流,点赞、留言、转发就是对我最大的回报和支持!

  • 相关阅读:
    python+django+uwsgi 搭建环境
    python系列-3 pyenv的使用
    生产消费者队列(TaskCompletionSource)的应用
    socket
    Redis 参考
    webform调用windows服务
    文件编码格式获取
    webform版部分视图与请求拦截
    asp.net 自定义节配置 (configSections下的section)
    组合配置草稿
  • 原文地址:https://www.cnblogs.com/xiaochuan94/p/11007474.html
Copyright © 2011-2022 走看看