Java LeetCode每日一题-从易到难带你领略算法的魅力(十三):整数转罗马数字

LeetCode每日一题 专栏收录该内容
21 篇文章 2 订阅

1.题目要求

  • 罗马数字包含以下七种字符: 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。这个特殊的规则只适用于以下六种情况:
    (1)I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
    (2)X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
    (3)C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
  • 给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。

2.题目示例

  • 示例 1:
输入: 3
输出: "III"
  • 示例 2:
输入: 4
输出: "IV"
  • 示例 3:
输入: 9
输出: "IX"
  • 示例 4:
输入: 58
输出: "LVIII"
解释: L = 50, V = 5, III = 3.
  • 示例 5:
输入: 1994
输出: "MCMXCIV"
解释: M = 1000, CM = 900, XC = 90, IV = 4.

3.提示

  • 要会做这道题首先你要知道罗马数字的符号以及一个简单的歧义处理逻辑
  • 首先罗马数字有7个单字母符号组成(题目描述中的代码块里有),此外根据减法规则(题目中有40、90…这种情况),我们可以把这类情况看做一个特殊符号来处理,所以我们一共得到了13个特殊符号
字符          数值
I             1
IV   		  4
V             5
IX  	 	  9
X             10
XL			  40
L             50
XC			  90
C             100
CD  		  400
D             500
CM			  900
M             1000
  • 其次是歧义处理逻辑,比如190的表达方式,可以有多种I-C的符号组成(相当于用1、4、5、9、10、40、50、90、100来组成190,将会有很多组合。190个1也是190 ),那么哪一种才是较为正确表示方法呢
  • 一般情况下,逻辑是从左到右选中尽可能大的符号表示可以直接在上面的13种符号中选择,所以190的表达方式为CXC

4.解题

4.1 解题思路

  1. 在读题以及了解了罗马数字的基本规则后,我们发现要把整数转罗马数字时,每一位都可以单独进行处理(个、十、白、千)。就可以对在每一位的符号进行分组,并进行枚举(题目规定了传入值范围)。
  2. 然后利用取模和除法运算,就可以得到每一位上的数字

4.2 业务代码

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

4.3 运行结果

结果

5.优化

5.1 优化思路

  1. 在第一题的基础上,我们还是考虑到要使用尽可能大的符号,从左侧开始。因此可以考虑贪心算法。
  2. 为了实现题意,我们去寻找给定数字当前可以减去的最大符号。然后减去之后,再去寻找,如此循环直到余数为0。
  3. 例子
//假设数组为191,那么可以取到的最大字符大小为100
191-100=91			C
//现在数字为91,那么可以取到的最大字符大小为90
91-90=1				XC
//现在数字为1,那么可以取到的最大字符大小为1,并且取值后余数为0.结束计算
1-1=0				I
//所以最后的结果为CXCI

5.2 优化业务代码

class Solution {
    int[] values = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};    
    String[] symbols = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};

    public String intToRoman(int num) {
        StringBuilder sb = new StringBuilder();
        // Loop through each symbol, stopping if num becomes 0.
        for (int i = 0; i < values.length && num >= 0; i++) {
            // Repeat while the current symbol still fits into num.
            while (values[i] <= num) {
                num -= values[i];
                sb.append(symbols[i]);
            }
        }
        return sb.toString();
    }
}

5.3 优化结果

结果

6.总结

  • 可以明显看见,在优化后差距还是挺大的
  • 大家有更好的方案可以在下面留言哟
  • 0
    点赞
  • 4
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
©️2020 CSDN 皮肤主题: 鲸 设计师:meimeiellie 返回首页

打赏

地球村公民

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值