整数和罗马数字之间的转换

⛑️ 整数和罗马数字之间的转换

罗马数字包含以下七种字符: IVXLCDM

字符 数值 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。

给你一个整数,将其转为罗马数字。

思路

基本思想

为了实现整数向罗马数字的转换,肯定需要一个映射关系,也就是需要建立一个哈希表,然后逐渐将数字拆分,没拆分依次就需要对应找到一个罗马字符表示拆分出来的部分,需要注意的是,拆分过程中需要遵循先拆大元素,再拆小元素的流程

需要注意的是,有六种特殊情况需要处理,所以可以再为这六种特殊情况添加六个新的映射,一旦有匹配的先匹配特殊情况,遵循从大到小的原则即可


为了实现罗马数字向整数的转换,需要注意的是,当罗马符号大的一般在左边,也就是高位,但是也有特殊情况,当大的在右边,也就是低位的时候就是特殊情况,所以需要单独处理这种特殊情况

注意到,当大的数在低位时,我们可以做减法,也就是当左边的数字小于右边的数字时,此时就出现了特殊情况,此时就不再是累加,需要减去当前位的数字,例如,给定一个IV,左边的I小于右边的V,此时遍历到I时,累加得到的结果是5,但是由于I小于右边的V,所以此时做减法,得到的结果为4,如果左边的值大于右边的值,此时正常做累加

执行流程

罗马数字转整数

  1. 从后向前遍历给定的罗马字符序列
  2. 当当前字符的值小于前一个字符的值,需要在整体结果的基础上减去当前字符代表的值,例如IV,当遍历到I时,需要减去I 的值
  3. 遍历结束返回最终的结果

整数转罗马数字

  1. 建立哈希表,一共十三种情况,包括正常的七种,加上特殊的六种
  2. 从大到小的尝试拆分给定的整数,没拆分一次得到一个罗马字符
  3. 拆分到整数为0时得到最终的结果

代码

罗马数字转整数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
    //从后向前遍历,当前位数字小于之前遍历的数字时,用结果减去当前位数字
    public int romanToInt(String s) {
        //创建一个映射表
        Map<Character,Integer> map=new HashMap<>();
        map.put('I',1);
        map.put('V',5);
        map.put('X',10);
        map.put('L',50);
        map.put('C',100);
        map.put('D',500);
        map.put('M',1000);
        int res=0;
        int pre=0;
        for(int i=s.length()-1;i>=0;--i){
            int temp=map.get(s.charAt(i));
            if(temp<pre)
                res-=temp;
            else
                res+=temp;
            pre=temp;
        }
        return res;
    }
}

整数转罗马数字

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Solution {
    //特殊情况分开处理,正常情况先处理
    public String intToRoman(int num) {
        Map<Integer,String> map=new HashMap<>();
        int[] nums={1000,900,500,400,100,90,50,40,10,9,5,4,1};
        String[] sinbol={"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
        String res="";
        for(int i=0;i<13;++i){
            //每一位符号都拆分的不能再拆分了之后,再进一步往小了拆分
            while(num>=nums[i]){
                num-=nums[i];
                res+=sinbol[i];
            }
        }
        return res;
    }
}

总结

整体总结下来就是两点:

  1. 罗马数字转整数时,从后向前遍历,当左边的数小于右边的数时做减法,左边的数大于右边的数时做加法
  2. 整数转罗马数字时,需要做好13种映射关系,然后先尽可能的把数拆分的够大,之后再往小了拆分,最后拆分到0就拆分成了,需要注意的时,因为存在特殊情况,拆分的顺序一定是:1000,900,500,400,100,90,50,40,10,9,5,4,1,不能乱,否则无法得到正确结果