Converting Roman Numerals To Decimal

2019-01-01 15:54发布

I have managed to get my code to convert most Roman numerals to its appropriate decimal value. But it doesn't work for some exceptional cases. Example : XCIX = 99 but my code prints 109.

Here is my code.

public static int romanConvert(String roman)
{
    int decimal = 0;

    String romanNumeral = roman.toUpperCase();
    for(int x = 0;x<romanNumeral.length();x++)
    {
        char convertToDecimal = roman.charAt(x);

        switch (convertToDecimal)
        {
        case 'M':
            decimal += 1000;
            break;

        case 'D':
            decimal += 500;
            break;

        case 'C':
            decimal += 100;
            break;

        case 'L':
            decimal += 50;
            break;

        case 'X':
            decimal += 10;
            break;

        case 'V':
            decimal += 5;
            break;

        case 'I':
            decimal += 1;
            break;
        }
    }
    if (romanNumeral.contains("IV"))
    {
        decimal-=2;
    }
    if (romanNumeral.contains("IX"))
    {
        decimal-=2;
    }
    if (romanNumeral.contains("XL"))
    {
        decimal-=10;
    }
    if (romanNumeral.contains("XC"))
    {
        decimal-=10;
    }
    if (romanNumeral.contains("CD"))
    {
        decimal-=100;
    }
    if (romanNumeral.contains("CM"))
    {
        decimal-=100;
    }
    return decimal;
}

标签: java
26条回答
何处买醉
2楼-- · 2019-01-01 16:24

Imperative + recursive solutions with validation step and online testing

To avoid useless calculations and to make sure the roman numerals format is correct, we need to check the input with a regular expression.

String regex = "^(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$";

Imperative solution

public static int romanToDecimal(String s) {
    if (s == null || s.isEmpty() || !s.matches("^(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$"))
        return -1;

    final Matcher matcher = Pattern.compile("M|CM|D|CD|C|XC|L|XL|X|IX|V|IV|I").matcher(s);
    final int[] decimalValues = {1000,900,500,400,100,90,50,40,10,9,5,4,1};
    final String[] romanNumerals = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
    int result = 0;

    while (matcher.find())
        for (int i = 0; i < romanNumerals.length; i++)
            if (romanNumerals[i].equals(matcher.group(0)))
                result += decimalValues[i];

    return result;
}

try online | try optimized version with comments/explanation online


UPDATE: here are two clever recursive proposals from this thread I solved adding validation step

Recursive solution 1 (original answer)

public class RomanToDecimalConverter {
    private static double evaluateNextRomanNumeral(String roman, int pos, double rightNumeral) {
        if (pos < 0) return 0;
        char ch = roman.charAt(pos);
        double value = Math.floor(Math.pow(10, "IXCM".indexOf(ch))) + 5 * Math.floor(Math.pow(10, "VLD".indexOf(ch)));
        return value * Math.signum(value + 0.5 - rightNumeral) + evaluateNextRomanNumeral(roman, pos - 1, value);
    }

    public static int evaluateRomanNumerals(String s) {
        if (s == null || s.isEmpty() || !s.matches("^(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$"))
            return -1;
        return (int) evaluateNextRomanNumeral(s, s.length() - 1, 0);
    }
}

try online

Recursive solution 2 (original answer)

public class RomanToDecimalConverter {
    private static int convertRec(String s) {
        if (s.isEmpty()) return 0;
             if (s.startsWith("M"))  return 1000 + convertRec(s.substring(1));
        else if (s.startsWith("CM")) return 900  + convertRec(s.substring(2));
        else if (s.startsWith("D"))  return 500  + convertRec(s.substring(1));
        else if (s.startsWith("CD")) return 400  + convertRec(s.substring(2));
        else if (s.startsWith("C"))  return 100  + convertRec(s.substring(1));
        else if (s.startsWith("XC")) return 90   + convertRec(s.substring(2));
        else if (s.startsWith("L"))  return 50   + convertRec(s.substring(1));
        else if (s.startsWith("XL")) return 40   + convertRec(s.substring(2));
        else if (s.startsWith("X"))  return 10   + convertRec(s.substring(1));
        else if (s.startsWith("IX")) return 9    + convertRec(s.substring(2));
        else if (s.startsWith("V"))  return 5    + convertRec(s.substring(1));
        else if (s.startsWith("IV")) return 4    + convertRec(s.substring(2));
        else if (s.startsWith("I"))  return 1    + convertRec(s.substring(1));
        throw new IllegalArgumentException("Unexpected roman numerals");
    }

    public static int convert(String s) {
        if (s == null || s.isEmpty() || !s.matches("^(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$"))
            return -1;
        return convertRec(s);
    }
}

try online

查看更多
看风景的人
3楼-- · 2019-01-01 16:24

I find the following approach a very intuitive one:

public void makeArray(String romanNumeral){
    int[] numberArray = new int[romanNumeral.length()];

    for(int i=0; i<romanNumeral.length();i++){
        char symbol = romanNumeral.charAt(i);
        switch(symbol){
            case 'I':
                numberArray[i] = 1;
                break;
            case 'V':
                numberArray[i] = 5;
                break;
            case 'X':
                numberArray[i] = 10;
                break;
            case 'L':
                numberArray[i] = 50;
                break;
            case 'C':
                numberArray[i] = 100;
                break;  
            case 'D':
                numberArray[i] = 500;
                break;   
            case 'M':
                numberArray[i] = 1000;
                break;       
        }
    }
    calculate(numberArray);
}
public static void calculate(int[] numberArray){
    int theNumber = 0;
    for(int n=0;n<numberArray.length;n++){         
        if(n !=numberArray.length-1 && numberArray[n] < numberArray[n+1]){
            numberArray[n+1] = numberArray[n+1] - numberArray[n];
            numberArray[n] = 0;                        
        }                 
    }
    for(int num:numberArray){
        theNumber += num;
    }
    System.out.println("Converted number: " + theNumber);

}
查看更多
登录 后发表回答