罗马数字和阿拉伯数字互化<java实现>

最近迷上了守望先锋,脑子一天不如一天,满脑子都是骚操作,所以闲的时候做一些ACM题目having some intellectual fun。然后就看到了这个:实现罗马数字与阿拉伯数字的互换。主要涉及的是字符串处理,没什么难度,自己做一做还是蛮有意思的。 我是用java实现的。

首先我们来看一下罗马数字的表数方法:
1.罗马数字采用七个罗马字母作数字、即Ⅰ(1)、X(10)、C(100)、M(1000)、V(5)、L(50)、D(500)
2.相同的数字连写,所表示的数等于这些数字相加得到的数,如 Ⅲ=3;
3.小的数字在大的数字的右边,所表示的数等于这些数字相加得到的数,如 Ⅷ=8、Ⅻ=12;小的数字(限于 Ⅰ、X 和 C)在大的数字的左边,所表示的数等于大数减小数得到的数,如 Ⅳ=4、Ⅸ=9;
4.正常使用时、连写的数字重复不得超过三次;
5.在一个数的上面画一条横线、表示这个数扩大 1000 倍。

注意以下几个规则:
1.基本数字 Ⅰ、X 、C 中的任何一个、自身连用构成数目、或者放在大数的右边连用构成数目、都不能超过三个;放在大数的左边只能用一个;
2.不能把基本数字 V 、L 、D 中的任何一个作为小数放在大数的左边采用相减的方法构成数目;放在大数的右边采用相加的方式构成数目、只能使用一个;
3.I只能用在V和X左边;X只能用在L和C左边;C只能用在D和M左边。

首先我们可以想一想这样的计数体系的特点是什么。因为不能输出上划线所以讨论过大的数没有意义,那么不用上划线所能表示的最大的数是多少呢?没错你应该已经想到了MMMCMXCIX——3999。这种计数体系的倍数关系并不明显,而加数关系更加明显。比如369,先表示300——CCC,然后60——LX,然后9——IX。连起来就是CCCLXIX。……

话不多说上程序。

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

阿拉伯数字转罗马数字主要就是按10进制位数决定每位字符就可以了。从罗马数字转阿拉伯数字就稍微繁琐一些,因为每个10进制位对应的字符串长度是不定的。我首先想到的是按位判断,每次判一个字符,然后加上相应的值,粗苯一些但是能工作:

public static int RomanToInt(String roman)
    int res=0;
    try {
        while(roman.charAt(0)=='M'){res+=1000;roman = roman.substring(1);}
        if(roman.charAt(0)=='D'){res+=500;roman = roman.substring(1);}
        while(roman.charAt(0)=='C'){res+=100;roman = roman.substring(1);}
        if(roman.charAt(0)=='D') {res+=300;roman = roman.substring(1);}
        else if(roman.charAt(0)=='M'){res+=800; roman = roman.substring(1);}
        if(roman.charAt(0)=='L'){res+=50;roman = roman.substring(1);}
        while(roman.charAt(0)=='X'){res+=10;roman=roman.substring(1);}
        if(roman.charAt(0)=='L'){res+=30;roman=roman.substring(1);}
        else if(roman.charAt(0)=='C'){res+=80;roman=roman.substring(1);}
        if(roman.charAt(0)=='V'){res+=5;roman=roman.substring(1);}
        while(roman.charAt(0)=='I'){res+=1;roman=roman.substring(1);}
        if(roman.charAt(0)=='V'){res+=3;roman=roman.substring(1);}
        else if(roman.charAt(0)=='X'){res+=8;roman= roman.substring(1);}
    } catch (StringIndexOutOfBoundsException e) {
            return res;
    }
    return res;
}

当字符串被截取成为了一个空串之后,再调用charAt(0)就会报错了,这个时候我们把它捕获,适时地返回已经得到的整数。
还有另外一个用到键值对和正则表达式的方法,马住下次再更。如有错误欢迎指正!博客求互粉:)

———————————我是二更的分界线——————————

public static int RomanToInt3(String Roman){
    int res = 0;
    String regex=null;
    String s = "'',0,I,1,II,2,III,3,IV,4,V,5,VI,6,VII,7,VIII,8,IX,9,X,10,XX,20,XXX,30,XL,40,L,50,LX,60,LXX,70,LXXX,80,XC,90,C,100,CC,200,CCC,300,CD,400,D,500,DC,600,DCC,700,DCCC,800,CM,900,M,1000,MM,2000,MMM,3000";
    String c[]=s.split(",");//将字符串打散,存入数组s
    Pattern p;//正则
        //遍历循环,正则匹配
    for(int t=c.length-2;t>0;t-=2){
        String roma = c[t];
        int value = Integer.parseInt(c[t+1]);
        regex="^("+roma+")";      p=Pattern.compile(regex,Pattern.CASE_INSENSITIVE);
        Matcher matcher=p.matcher(Roman);
        if(matcher.find()){
            res += value;
           Roman=Roman.substring(((String)roma).length());
//              System.out.print(Roman + "\t\t");
//              System.out.print(regex + "\t\t");
//              System.out.println(res);
        }
    }
    return res;
}

本来想用Map存储键值对,但是遍历Map中的元素用到的Iterator不是根据放入的键值对先后顺序进行遍历的,而是根据字母表顺序。也就是每次遍历时先找C,再找CC……这就很尴尬,因为CM的话是表示900,而Iterator会先找到C,再找到M,就变成了1100。所以我就直接用了一个字符串数组,从大到小遍历,这样从高位到地位是不会产生罗马数字歧义的。正则表达式确实是字符串处理的利器。

猜你喜欢

转载自blog.csdn.net/geek_geeker/article/details/53266663