算法刷题3-罗马数转整数(leetcode13)

2020年4月3日。目前自我评价为中级小白;

题目描述


罗马数字包含以下七种字符: 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。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。 
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。

示例 1:

输入: s = "III"
输出: 3
示例 2:

输入: s = "IV"
输出: 4
示例 3:

输入: s = "IX"
输出: 9
示例 4:

输入: s = "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3.
示例 5:

输入: s = "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.
 

提示:

1 <= s.length <= 15
s 仅含字符 ('I', 'V', 'X', 'L', 'C', 'D', 'M')
题目数据保证 s 是一个有效的罗马数字,且表示整数在范围 [1, 3999] 内
题目所给测试用例皆符合罗马数字书写规则,不会出现跨位等情况。
IL 和 IM 这样的例子并不符合题目要求,49 应该写作 XLIX,999 应该写作 CMXCIX 。
关于罗马数字的详尽书写规则,可以参考 罗马数字 - Mathematics 。

 这个题初看还是比较懵的,也没有思路,但是可以初步确定的就是肯定要有一个能获取到对应罗马数字所代表的阿拉伯数字的数组。也就是

 String luoma = "IVXLCDM";
 int[] num = new int[]{1,5,10,50,100,500,1000};

也就是字符串中字符所在的索引在下面的数字数组中可以获取相对应的数值,以便后边计算。

但是这里面有两种情况,一种的获取到元素找到对应数值然后相加,是属于普通情况。另一种就是类似于4,9这样的数,也就是题目中提到的这段:

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 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。
给定一个罗马数字,将其转换成整数。

 所以这道题要分两种情况去解决,一种的是正常情况,另一种就是这六种特殊情况。我们先看正常情况,我们只需要用

int index = 字符串.indexOf(对应字符);
int  value = num[index];

然后用一个提前定义好的sum总和累加即可。

另一种情况就是非正常情况了,也就是上面说的那六种情况,经过分析我们可以知道,这种特殊情况的字母排序,是两个字母在一起算做一个数值,也就是后面罗马数字对应的阿拉伯数字减去前面罗马数字对应的阿拉伯数字。所以,在这种情况要对相邻的两个罗马字母进行判断。后面的索引值减前面的索引值等于1或者2的话,就是属于特殊情况。将传入的罗马数字转换成字符数组后循环后,在循环体中就可以这样判断:

展示:(部分,完整版在后面)

if (luoma.indexOf(chars[i+1]) - luoma.indexOf(chars[i]) == 1 ||
    luoma.indexOf(chars[i+1]) - luoma.indexOf(chars[i]) == 2){
    int big = luoma.indexOf(chars[i+1]);
    int small = luoma.indexOf(chars[i]);
    value = num[big] - num[small];

这样的话就可以将特殊情况给分出来,但是要注意一点,当这个循环的i变成length-1的时候,再用i+1的话,就会报数组索引越界异常,所以就要提前进行判断:

if (i != chars.length-1){
   if (luoma.indexOf(chars[i+1]) - luoma.indexOf(chars[i]) == 1 ||
       luoma.indexOf(chars[i+1]) - luoma.indexOf(chars[i]) == 2){
           int big = luoma.indexOf(chars[i+1]);
           int small = luoma.indexOf(chars[i]);
           value = num[big] - num[small];
           i++;
       }else{
           int index =  luoma.indexOf(chars[i]);
           value = num[index];
       }
}else{
       int index =  luoma.indexOf(chars[i]);
       value = num[index];
}

这样的话就可以将两种情况都包含进去了。最后只需要将每次循环体中不同的value进行累加就行了。

完整代码展示如下:

 public int romanToInt(String s) {
        String luoma = "IVXLCDM";
        int[] num = new int[]{1,5,10,50,100,500,1000};
        int sum = 0;
            char[] chars = s.toCharArray();
            for (int i = 0; i < chars.length; i++) {
                int value = 0;
                if (i != chars.length-1){
                    if (luoma.indexOf(chars[i+1]) - luoma.indexOf(chars[i]) == 1 ||
                        luoma.indexOf(chars[i+1]) - luoma.indexOf(chars[i]) == 2){
                       int big = luoma.indexOf(chars[i+1]);
                       int small = luoma.indexOf(chars[i]);
                       value = num[big] - num[small];
                       i++;
                    }else{
                        int index =  luoma.indexOf(chars[i]);
                        value = num[index];
                    }
                }else{
                   int index =  luoma.indexOf(chars[i]);
                   value = num[index];
                }
                sum += value;
            }
        return sum;
    }

 哈哈,是不是很棒,我可真是个小天才。好啦,就这样啦。写这个题比我刚开始预想的要快很多,并且发现了要边写边思考,也不能只思考,边写边思考思路会拓宽很多。好啦,本算法结束。向下一关出发!!!加油,奥力给!!!


版权声明:本文为weixin_65549694原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。