将罗马数字转换为十进制

时间:2012-01-31 01:08:44

标签: java

我设法让我的代码将大多数罗马数字转换为适当的十进制值。但它不适用于某些特殊情况。示例:XCIX = 99,但我的代码打印为109

这是我的代码。

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;
}

29 个答案:

答案 0 :(得分:57)

如果你反过来走路会很好。

public class RomanToDecimal {
    public static void romanToDecimal(java.lang.String romanNumber) {
        int decimal = 0;
        int lastNumber = 0;
        String romanNumeral = romanNumber.toUpperCase();
        /* operation to be performed on upper cases even if user 
           enters roman values in lower case chars */
        for (int x = romanNumeral.length() - 1; x >= 0 ; x--) {
            char convertToDecimal = romanNumeral.charAt(x);

            switch (convertToDecimal) {
                case 'M':
                    decimal = processDecimal(1000, lastNumber, decimal);
                    lastNumber = 1000;
                    break;

                case 'D':
                    decimal = processDecimal(500, lastNumber, decimal);
                    lastNumber = 500;
                    break;

                case 'C':
                    decimal = processDecimal(100, lastNumber, decimal);
                    lastNumber = 100;
                    break;

                case 'L':
                    decimal = processDecimal(50, lastNumber, decimal);
                    lastNumber = 50;
                    break;

                case 'X':
                    decimal = processDecimal(10, lastNumber, decimal);
                    lastNumber = 10;
                    break;

                case 'V':
                    decimal = processDecimal(5, lastNumber, decimal);
                    lastNumber = 5;
                    break;

                case 'I':
                    decimal = processDecimal(1, lastNumber, decimal);
                    lastNumber = 1;
                    break;
            }
        }
        System.out.println(decimal);
    }

    public static int processDecimal(int decimal, int lastNumber, int lastDecimal) {
        if (lastNumber > decimal) {
            return lastDecimal - decimal;
        } else {
            return lastDecimal + decimal;
        }
    }

    public static void main(java.lang.String args[]) {
        romanToDecimal("XIV");
    }
}

答案 1 :(得分:39)

试试这个 - 它简单而紧凑,工作非常顺利:

    public static int ToArabic(string number) {
        if (number == string.Empty) return 0;
        if (number.StartsWith("M")) return 1000 + ToArabic(number.Remove(0, 1));
        if (number.StartsWith("CM")) return 900 + ToArabic(number.Remove(0, 2));
        if (number.StartsWith("D")) return 500 + ToArabic(number.Remove(0, 1));
        if (number.StartsWith("CD")) return 400 + ToArabic(number.Remove(0, 2));
        if (number.StartsWith("C")) return 100 + ToArabic(number.Remove(0, 1));
        if (number.StartsWith("XC")) return 90 + ToArabic(number.Remove(0, 2));
        if (number.StartsWith("L")) return 50 + ToArabic(number.Remove(0, 1));
        if (number.StartsWith("XL")) return 40 + ToArabic(number.Remove(0, 2));
        if (number.StartsWith("X")) return 10 + ToArabic(number.Remove(0, 1));
        if (number.StartsWith("IX")) return 9 + ToArabic(number.Remove(0, 2));
        if (number.StartsWith("V")) return 5 + ToArabic(number.Remove(0, 1));
        if (number.StartsWith("IV")) return 4 + ToArabic(number.Remove(0, 2));
        if (number.StartsWith("I")) return 1 + ToArabic(number.Remove(0, 1));
        throw new ArgumentOutOfRangeException("something bad happened");
    }

答案 2 :(得分:24)

假设哈希看起来像这样

Hashtable<Character, Integer> ht = new Hashtable<Character, Integer>();
    ht.put('i',1);
    ht.put('x',10);
    ht.put('c',100);
    ht.put('m',1000);
    ht.put('v',5);
    ht.put('l',50);
    ht.put('d',500);

然后逻辑变得非常简单,从右到左依次为

public static int rtoi(String num)
{       
    int intNum=0;
    int prev = 0;
    for(int i = num.length()-1; i>=0 ; i--)
    {
            int temp = ht.get(num.charAt(i));
            if(temp < prev)
                intNum-=temp;
            else
                intNum+=temp;
            prev = temp;
    }
    return intNum;
}   

答案 3 :(得分:4)

遵循在IX上减少2的逻辑,你应该在CM上的XC 200上减少20,依此类推。

答案 4 :(得分:3)

代码更少,效率更高。不太清楚,抱歉!

public int evaluateRomanNumerals(String roman) {
    return (int) evaluateNextRomanNumeral(roman, roman.length() - 1, 0);
}

private 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);
}

答案 5 :(得分:3)

具有验证步骤和在线测试的势在必行的递归解决方案

为了避免无用的计算并确保罗马数字格式正确,我们需要使用正则表达式检查输入。

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

势在必行的解决方案

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


更新:这里有两个聪明的递归提案,我解决了添加验证步骤

递归解决方案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

递归解决方案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

答案 6 :(得分:2)

// Author: Francisco Edmundo
private int translateNumber(String texto) {
    int n = 0;
    int numeralDaDireita = 0;
    for (int i = texto.length() - 1; i >= 0; i--) {
        int valor = (int) translateNumber(texto.charAt(i));
        n += valor * Math.signum(valor + 0.5 - numeralDaDireita);
        numeralDaDireita = valor;
    }
    return n;
}
private double translateNumber(char caractere) {
    return Math.floor(Math.pow(10, "IXCM".indexOf(caractere))) + 5 * Math.floor(Math.pow(10, "VLD".indexOf(caractere)));
}

答案 7 :(得分:2)

您可以查看以下代码。此代码应适用于所有情况。它还会检查null或空输入和错误输入(假设您尝试使用ABXI)

import java.util.HashMap;
import org.apache.commons.lang3.StringUtils;

public class RomanToDecimal {
  private HashMap<Character, Integer> map;

  public RomanToDecimal() {
    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);
  }

  private int getRomanNumeralValue(char ch) {
    if (map.containsKey(ch)) {
      return map.get(ch);
    }
    else {
      throw new RuntimeException("Roman numeral string contains invalid characters " + ch);
    }
  }

  public int convertRomanToDecimal(final String pRomanNumeral) {
    if (StringUtils.isBlank(pRomanNumeral)) {
      throw new RuntimeException("Roman numeral string is either null or empty");
    }
    else {
      int index = pRomanNumeral.length() - 1;
      int result = getRomanNumeralValue(pRomanNumeral.charAt(index));

      for (int i = index - 1; i >= 0; i--) {
        if (getRomanNumeralValue(pRomanNumeral.charAt(i)) >= getRomanNumeralValue(pRomanNumeral.charAt(i + 1))) {
          result = result + getRomanNumeralValue(pRomanNumeral.charAt(i));
        }
        else {
          result = result - getRomanNumeralValue(pRomanNumeral.charAt(i));
        }
      }
      return result;
    }
  }
public static void main(String... args){
      System.out.println(new RomanToDecimal().convertRomanToDecimal("XCIX"));
  }

}

答案 8 :(得分:1)

尽管已经提出了许多解决方案。

我想下面的内容简短明了:

public class RomanToInteger {
    public static int romanToInt(String roman) {
        final Map<Character, Integer> map = Map.of('I', 1,
                'V', 5,
                'X', 10,
                'L', 50,
                'C', 100,
                'D', 500,
                'M', 1000);

        int result = 0;
        for (int index = 0; index < roman.length(); index++) {
            final int curNumber = map.get(roman.charAt(index));

            if (index > 0 && curNumber > map.get(roman.charAt(index - 1))) {
                // add current number & remove previous one twice:
                // first: we add it before (when it was current number) and removing it for this current number
                // second: for correct conversion to roman numbers
                result += curNumber - 2 * map.get(roman.charAt(index - 1));
            } else {
                result += curNumber;
            }
        }
        System.out.printf("%8s -> %4d\n", roman, result);
        return result;
    }

    public static void main(String[] args) {
        String[] romans = {"I", "II", "III", "V", "X", "XIV", "XVII", "XX", "XXV",
                "XXX", "XXXVIII", "XLIX", "LXIII", "LXXXI", "XCVII", "XCVIII", "XCIX",
                "C", "CI", "CCXLVIII", "CCLIII", "DCCXCIX", "MCCCXXV", "MCM", "MM",
                "MMCDLVI", "MDCCXV"};

        final Instant startTimeIter = Instant.now();
        for (String roman : romans) {
            romanToInt(roman);
        }
        final Instant endTimeIter = Instant.now();

        System.out.printf("Elapsed time: %d ms\n", Duration.between(startTimeIter, endTimeIter).toMillis());
    }
}

输出:

       I ->    1
      II ->    2
     III ->    3
     ...
 MMCDLVI -> 2456
  MDCCXV -> 1715
Elapsed time: 101 ms

逻辑很简单,我们只需从左到右通过罗马文字:

  • 如果文字不是第一个且前一个数字较低->我们必须将当前数字加到total并提取前一个数字两次。第一次,是我们在上一步中添加的内容(当它是当前数字时)。第二,因为这是罗马文字转换的规则(例如IX文字)。
  • 否则,只需将其添加到总结果中即可。

答案 9 :(得分:1)

具有错误检查功能的完整版本,并在两个方向(以及一些无效情况)下测试所有有效值。

RomanNumeral.java

import java.util.ArrayList;
import java.util.TreeMap;

/**
 * Convert to and from a roman numeral string
 */
public class RomanNumeral {

    // used for converting from arabic number
    final static TreeMap<Integer, String> mapArabic = new TreeMap<Integer, String>();
    // used for converting from roman numeral
    final static ArrayList<RomanDigit> mapRoman = new ArrayList<RomanDigit>();
    final static int MAX_ARABIC = 3999;

    static {
        mapArabic.put(1000, "M");
        mapArabic.put(900, "CM");
        mapArabic.put(500, "D");
        mapArabic.put(400, "CD");
        mapArabic.put(100, "C");
        mapArabic.put(90, "XC");
        mapArabic.put(50, "L");
        mapArabic.put(40, "XL");
        mapArabic.put(10, "X");
        mapArabic.put(9, "IX");
        mapArabic.put(5, "V");
        mapArabic.put(4, "IV");
        mapArabic.put(1, "I");

        mapRoman.add(new RomanDigit("M", 1000, 3, 1000));
        mapRoman.add(new RomanDigit("CM", 900, 1, 90));
        mapRoman.add(new RomanDigit("D", 500, 1, 100));
        mapRoman.add(new RomanDigit("CD", 400, 1, 90));
        mapRoman.add(new RomanDigit("C", 100, 3, 100));
        mapRoman.add(new RomanDigit("XC", 90, 1, 9));
        mapRoman.add(new RomanDigit("L", 50, 1, 10));
        mapRoman.add(new RomanDigit("XL", 40, 1, 9));
        mapRoman.add(new RomanDigit("X", 10, 3, 10));
        mapRoman.add(new RomanDigit("IX", 9, 1, 0));
        mapRoman.add(new RomanDigit("V", 5, 1, 1));
        mapRoman.add(new RomanDigit("IV", 4, 1, 0));
        mapRoman.add(new RomanDigit("I", 1, 3, 1));
    }

    static final class RomanDigit {
        public final String numeral;
        public final int value;
        public final int maxConsecutive;
        public final int maxNextValue;

        public RomanDigit(String numeral, int value, int maxConsecutive, int maxNextValue) {
            this.numeral = numeral;
            this.value = value;
            this.maxConsecutive = maxConsecutive;
            this.maxNextValue = maxNextValue;
        }
    }

    /**
     * Convert an arabic integer value into a roman numeral string
     *
     * @param n The arabic integer value
     * @return The roman numeral string
     */
    public final static String toRoman(int n) {
        if (n < 1 || n > MAX_ARABIC) {
            throw new NumberFormatException(String.format("Invalid arabic value: %d, must be > 0 and < %d", n, MAX_ARABIC));
        }

        int leDigit = mapArabic.floorKey(n);
        //System.out.println("\t*** floor of " + n + " is " + leDigit);
        if (n == leDigit) {
            return mapArabic.get(leDigit);
        }
        return mapArabic.get(leDigit) + toRoman(n - leDigit);
    }

    /**
     * Convert a roman numeral string into an arabic integer value
     * @param s The roman numeral string
     * @return The arabic integer value
     */
    public final static int toInt(String s) throws NumberFormatException {
        if (s == null || s.length() == 0) {
            throw new NumberFormatException("Invalid roman numeral: a non-empty and non-null value must be given");
        }

        int i = 0;
        int iconsecutive = 0; // number of consecutive same digits
        int pos = 0;
        int sum = 0;
        RomanDigit prevDigit = null;

        while (pos < s.length()) {

            RomanDigit d = mapRoman.get(i);
            if (!s.startsWith(mapRoman.get(i).numeral, pos)) {
                i++;
                // this is the only place we advance which digit we are checking,
                // so if it exhausts the digits, then there is clearly a digit sequencing error or invalid digit
                if (i == mapRoman.size()) {
                    throw new NumberFormatException(
                            String.format("Invalid roman numeral at pos %d: invalid sequence '%s' following digit '%s'",
                                    pos, s.substring(pos), prevDigit != null ? prevDigit.numeral : ""));
                }
                iconsecutive = 0;
                continue;
            }

            // we now have the match for the next roman numeral digit to check
            iconsecutive++;
            if (iconsecutive > d.maxConsecutive) {
                throw new NumberFormatException(
                        String.format("Invalid roman numeral at pos %d: more than %d consecutive occurences of digit '%s'",
                                pos, d.maxConsecutive, d.numeral));
            }

            // invalid to encounter a higher digit sequence than the previous digit expects to have follow it
            // (any digit is valid to start a roman numeral - i.e. when prevDigit == null)
            if (prevDigit != null && prevDigit.maxNextValue < d.value) {
                throw new NumberFormatException(
                        String.format("Invalid roman numeral at pos %d: '%s' cannot follow '%s'",
                                pos, d.numeral, prevDigit.numeral));
            }

            // good to sum
            sum += d.value;
            if (sum > MAX_ARABIC) {
                throw new NumberFormatException(
                        String.format("Invalid roman numeral at pos %d: adding '%s' exceeds the max value of %d",
                                pos, d.numeral, MAX_ARABIC));
            }
            pos += d.numeral.length();
            prevDigit = d;
        }

        return sum;
    }
}

Main.java

public class Main {
    public static void main(String[] args) {

        System.out.println("TEST arabic integer => roman numeral string");
        for (int i = 0; i<= 4000; i++) {
            String s;
            try {
                s = RomanNumeral.toRoman(i);
            }
            catch(NumberFormatException ex) {
                s = ex.getMessage();
            }
            System.out.println(i + "\t =\t " + s);
        }

        System.out.println("TEST roman numeral string => arabic integer");
        for (int i = 0; i<= 4000; i++) {
            String s;
            String msg;
            try {
                s = RomanNumeral.toRoman(i);
                int n = testToInt(s);
                assert(i == n); // ensure it is reflexively converting
            }
            catch (NumberFormatException ex) {
                System.out.println(ex.getMessage() + "\t =\t toInt() skipped");
            }
        }

        testToInt("MMMM");
        testToInt("XCX");
        testToInt("CDC");
        testToInt("IVI");
        testToInt("XXC");
        testToInt("CCD");
        testToInt("MDD");
        testToInt("DD");
        testToInt("CLL");
        testToInt("LL");
        testToInt("IIX");
        testToInt("IVX");
        testToInt("IIXX");
        testToInt("XCIX");
        testToInt("XIWE");

        // Check validity via a regexp for laughs
        String s = "IX";
        System.out.println(s + " validity is " + s.matches("M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})"));
    }

    private final static int testToInt(String s) {
        String msg;
        int n=0;
        try {
            n = RomanNumeral.toInt(s);
            msg = Integer.toString(n);
        }
        catch(NullPointerException | NumberFormatException ex) {
            msg = ex.getMessage();
        }

        System.out.println(s + "\t =\t " + msg);
        return n;
    }
}

输出

TEST arabic integer => roman numeral string
0    =   Invalid arabic value: 0, must be > 0 and < 3999
1    =   I
2    =   II
3    =   III
4    =   IV
5    =   V
6    =   VI
7    =   VII
8    =   VIII
9    =   IX
10   =   X
... [snip] ...
3988     =   MMMCMLXXXVIII
3989     =   MMMCMLXXXIX
3990     =   MMMCMXC
3991     =   MMMCMXCI
3992     =   MMMCMXCII
3993     =   MMMCMXCIII
3994     =   MMMCMXCIV
3995     =   MMMCMXCV
3996     =   MMMCMXCVI
3997     =   MMMCMXCVII
3998     =   MMMCMXCVIII
3999     =   MMMCMXCIX
4000     =   Invalid arabic value: 4000, must be > 0 and < 3999
TEST roman numeral string => arabic integer
Invalid arabic value: 0, must be > 0 and < 3999  =   toInt() skipped
I    =   1
II   =   2
III  =   3
IV   =   4
V    =   5
VI   =   6
VII  =   7
VIII     =   8
IX   =   9
X    =   10
... [snip] ...
MMMCMLXXXVIII    =   3988
MMMCMLXXXIX  =   3989
MMMCMXC  =   3990
MMMCMXCI     =   3991
MMMCMXCII    =   3992
MMMCMXCIII   =   3993
MMMCMXCIV    =   3994
MMMCMXCV     =   3995
MMMCMXCVI    =   3996
MMMCMXCVII   =   3997
MMMCMXCVIII  =   3998
MMMCMXCIX    =   3999
Invalid arabic value: 4000, must be > 0 and < 3999   =   toInt() skipped
MMMM     =   Invalid roman numeral at pos 3: more than 3 consecutive occurences of digit 'M'
XCX  =   Invalid roman numeral at pos 2: 'X' cannot follow 'XC'
CDC  =   Invalid roman numeral at pos 2: 'C' cannot follow 'CD'
IVI  =   Invalid roman numeral at pos 2: 'I' cannot follow 'IV'
XXC  =   Invalid roman numeral at pos 2: invalid sequence 'C' following digit 'X'
CCD  =   Invalid roman numeral at pos 2: invalid sequence 'D' following digit 'C'
MDD  =   Invalid roman numeral at pos 2: more than 1 consecutive occurences of digit 'D'
DD   =   Invalid roman numeral at pos 1: more than 1 consecutive occurences of digit 'D'
CLL  =   Invalid roman numeral at pos 2: more than 1 consecutive occurences of digit 'L'
LL   =   Invalid roman numeral at pos 1: more than 1 consecutive occurences of digit 'L'
IIX  =   Invalid roman numeral at pos 2: invalid sequence 'X' following digit 'I'
IVX  =   Invalid roman numeral at pos 2: invalid sequence 'X' following digit 'IV'
IIXX     =   Invalid roman numeral at pos 2: invalid sequence 'XX' following digit 'I'
XCIX     =   99
XIWE     =   Invalid roman numeral at pos 2: invalid sequence 'WE' following digit 'I'
IX validity is true

答案 10 :(得分:1)

让我们用3种不同的场景来看待这个问题

  

情景1:

当我们看到如下图案时

'IIIIII' or 'XXXXX'  or 'CCCC'

其中所有字符都相同:我们在模式中添加每个字符的值

'IIIIII' gives us '6'

'XXXXX' gives us '50'

'CCCC' gives us '400'
  

情景2:

当我们看到任何2个连续字符不同时,其中第一个值的值小于第二个

'IX' or 'XC'

我们从第二个中减去第一个值。

second:'X' gives us '10'

first: 'I' gives us '1'

second  - first :  10 - 1 = 9
  

情景3:

当我们看到任何2个连续字符不同时,第一个值大于第二个

'XI' or 'CX'

我们添加第一个和第二个例如

second:'I' gives us '10'
first: 'X' gives us '1'
first  + second :  10 +  1 = 11

现在我们可以找到结果,如果我们递归地执行此操作。 这是java实现:

//An array to be used for faster comparisons and reading the values
private int[] letters26 = new int[26];
private void init () {
    letters26['I' - 'A'] = 1;
    letters26['V' - 'A'] = 5;
    letters26['X' - 'A'] = 10;
    letters26['L' - 'A'] = 50;
    letters26['C' - 'A'] = 100;
    letters26['D' - 'A'] = 500;
    letters26['M' - 'A'] = 1000;
}

public int convertRomanToInteger(String s) {
    //Initialize the array
    init();
    return _convertRomanToInteger(s.toCharArray(), 0);
}

//Recursively  calls itself as long as 2 consecutive chars are different
private int _convertRomanToInteger(char[] s, int index) {
    int ret = 0;
    char pre = s[index];//Char from the given index
    ret = _getValue(pre);

    //Iterate through the rest of the string 
    for (int i = index + 1; i < s.length; i++) {
        if (compare(s[i], s[i - 1]) == 0) {
            //Scenario 1:
            //If 2 consecutive chars are similar, just add them             
            ret += _getValue(s[i]);
        } else if (compare(s[i], s[i - 1]) > 0) {
            //Scenario 2:
            //If current char is greater than the previous e.g IX ('I' s[i - 1] and 'X' s[i - 1])
            //We need to calculate starting from 'i' and subtract the calculation ('ret') 
            //done so far in current call
            return _convertRomanToInteger(s, i) - ret;
        } else {
            //Scenario 3:
            //If current char is smaller than the previous e.g XI ('X' s[i - 1] and 'I' s[i - 1])
            //We need to calculate starting from 'i' and subtract the result 
            //from the calculation done so far in current call
            return ret + _convertRomanToInteger(s, i);
        }
    }
    return ret;
}

//Helper function for comparison
private int compare(char a, char b) {
    return letters26[Character.toUpperCase(a) - 'A']
            - letters26[Character.toUpperCase(b) - 'A'];
}

private int _getValue(char c) {
    return letters26[Character.toUpperCase(c) - 'A']; 
}

答案 11 :(得分:0)

public static int convertFromRoman(String romanNumeral)
{
    Character[] rnChars = { 'M',  'D', 'C',   'L',  'X',  'V', 'I' };
    int[] rnVals = {  1000,  500, 100,  50, 10, 5, 1 };
    HashMap<Character, Integer> valueLookup = new HashMap<Character, Integer>();
    for (int i = 0; i < rnChars.length;i++)
        valueLookup.put(rnChars[i], rnVals[i]);
    int retVal = 0;
    for (int i = 0; i < romanNumeral.length();i++)
    {
        int addVal = valueLookup.get(romanNumeral.charAt(i));
        retVal += i < romanNumeral.length()-1 && 
                  addVal < valueLookup.get(romanNumeral.charAt(i+1))?
                  -addVal:addVal;
    }
    return retVal;
}

答案 12 :(得分:0)

输入范围从1到3999的简便解决方案。

    private static final Map<String, Integer> MAPPING = new HashMap<>() {{
    put("I", 1);
    put("V", 5);
    put("X", 10);
    put("L", 50);
    put("C", 100);
    put("D", 500);
    put("M", 1000);
    put("IV", 4);
    put("IX", 9);
    put("XL", 40);
    put("XC", 90);
    put("CD", 400);
    put("CM", 900);
}};

public static int romanToInt(String s) {
    int sum = 0;
    for (int i = 0; i < s.length(); i++) {
        if (i < s.length() - 1 && MAPPING.containsKey(String.valueOf(s.charAt(i)) + s.charAt(i + 1))) {
            sum += MAPPING.get(String.valueOf(s.charAt(i)) + s.charAt(i + 1));
            i++;
        } else {
            sum += MAPPING.get(String.valueOf(s.charAt(i)));
        }
    }
    return sum;
}

答案 13 :(得分:0)

只有两个if语句优先检查第一个字符的匹配情况,如果不匹配,则匹配单个第一个字符

public class Solution {
    private static TreeMap<String, Integer> numeralsAndVal;
    static{
        numeralsAndVal = new TreeMap<>();
        numeralsAndVal.put("M", 1000);
        numeralsAndVal.put("CM", 900);
        numeralsAndVal.put("D", 500);
        numeralsAndVal.put("CD", 400);
        numeralsAndVal.put("C", 100);
        numeralsAndVal.put("XC", 90);
        numeralsAndVal.put("L", 50);
        numeralsAndVal.put("XL", 40);
        numeralsAndVal.put("X", 10);
        numeralsAndVal.put("IX", 9);
        numeralsAndVal.put("V", 5);
        numeralsAndVal.put("IV", 4);
        numeralsAndVal.put("I", 1);
    }
    public int romanToInt(String A) {
        if (A.length() == 0) return 0;
        if (A.length() >= 2 && numeralsAndVal.containsKey(A.substring(0, 2))){
            return numeralsAndVal.get(A.substring(0, 2)) + romanToInt(A.substring(2));
        }
        return numeralsAndVal.get(A.substring(0, 1)) + romanToInt(A.substring(1));
    }
}

答案 14 :(得分:0)

使用尾递归的解决方案:

import java.util.LinkedHashMap;

public class RomanNumber {

private final static LinkedHashMap<String, Integer> roman2number = new LinkedHashMap<>(); // preserve key order

static {
    roman2number.put("M", 1000);
    roman2number.put("CM", 900);
    roman2number.put("D", 500);
    roman2number.put("CD", 400);
    roman2number.put("C", 100);
    roman2number.put("XC", 90);
    roman2number.put("L", 50);
    roman2number.put("XL", 40);
    roman2number.put("X", 10);
    roman2number.put("IX", 9);
    roman2number.put("V", 5);
    roman2number.put("IV", 4);
    roman2number.put("I", 1);
}

public final static Integer toDecimal(String roman) {
    for (String key : roman2number.keySet()) {
        if (roman.startsWith(key)) {
            if (roman.equals(key)) {
                return roman2number.get(key);
            }
            return roman2number.get(key) + toDecimal(roman.substring(key.length()));
        }
    }
    return 0;
}
}

测试:

import junitparams.JUnitParamsRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import junitparams.Parameters;
import static org.junit.Assert.assertTrue;

@RunWith(JUnitParamsRunner.class)
public class RomanNumberTest {

@Test
@Parameters({ "1|I", "2|II", "3|III", "4|IV", "5|V", "6|VI", "7|VII", "8|VIII", "9|IX", "10|X",
        "11|XI", "12|XII", "13|XIII", "14|XIV", "15|XV", "16|XVI", "17|XVII", "18|XVIII", "19|XIX",
        "20|XX", "50|L", "53|LIII", "57|LVII", "40|XL", "49|XLIX", "59|LIX", "79|LXXIX", "100|C", "90|XC", "99|XCIX",
        "200|CC", "500|D", "499|CDXCIX", "999|CMXCIX", "2999|MMCMXCIX", "3999|MMMCMXCIX"
})
public void forRomanReturnsNumber(int number, String roman) {
    assertTrue(roman + "->" + number, RomanNumber.toDecimal(roman) == (number));
}

}

答案 15 :(得分:0)

scala解决方案可能很有用:

class RomanNumberConverter {

  private val toArabic = Map('I' -> 1, 'V' -> 5, 'X' -> 10, 'L' -> 50, 'C' -> 100, 'D' -> 500, 'M' -> 1000)

  // assume that correct roman number is provided
  def convert(romanNumber: String): Int = {
    def convert(rn: StringBuilder, lastDecimal: Int, acc: Int): Int = {
      if (rn.isEmpty) acc
      else {
        val thisDecimal = toArabic(rn.head)
        if (thisDecimal > lastDecimal) convert(rn.tail, thisDecimal, acc + thisDecimal - lastDecimal - lastDecimal)
        else convert(rn.tail, thisDecimal, acc + thisDecimal)
      }
    }

    val sb = new StringBuilder(romanNumber)
    convert(sb.tail, toArabic(sb.head), toArabic(sb.head))
  }

}

答案 16 :(得分:0)

public class RomanNumeral {

private final Map<Integer, String> arabicToRoman = new LinkedHashMap<Integer, String>();
private final Map<String, Integer> romanToArabic = new LinkedHashMap<String, Integer>();

public RomanNumeral() {
    arabicToRoman.put(10, "X");
    arabicToRoman.put(9, "IX");
    arabicToRoman.put(5, "V");
    arabicToRoman.put(4, "IV");
    arabicToRoman.put(1, "I");
    romanToArabic.put("X", 10);
    romanToArabic.put("V", 5);
    romanToArabic.put("I", 1);
}

public String convertToRomanNumeral(int number) {
    String result = "";

    for (Integer i : arabicToRoman.keySet()) {
        while (number >= i) {
            result += arabicToRoman.get(i);
            number -= i;
        }
    }

    return result;
}

public String convertToArabicNumber(String romanNumeral) {
    int result = 0;

    int top = 0;
    for (int i = romanNumeral.length() - 1; i >= 0; i--) {
        char current = romanNumeral.charAt(i);
        int value = romanToArabic.get("" + current);
        if (value < top) {
            result -= value;
        } else {
            result += value;
            top = value;
        }
    }

    return "" + result;
}

}

答案 17 :(得分:0)

This is a modest variation of the recursive algorithm suggested by Sahtiel:

public static int toArabic(String number) throws Exception {
    String[] letras = {"M","CM","D","CD","C","XC","L","XL","X", "IX","V","IV","I"};
    int[] valores = {1000,900,500,400,100,90,50,40,10,9,5,4,1};

    // here we can do even more business validations like avoiding sequences like XXXXM
    if (number==null || number.isEmpty()) {
        return 0;
    }
    for(int i=0; i<letras.length; i++) {
        if (number.startsWith(letras[i])) {
            return valores[i] + toArabic(number.substring(letras[i].length()));
        }
    }
    throw new Exception("something bad happened");
}

It uses less than 10 effective lines of code.

答案 18 :(得分:0)

我发现以下方法非常直观:

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);

}

答案 19 :(得分:0)

这是您对所有测试用例的要求和工作的非常基本的实现。如果你发现它有什么不对的话,我会尝试使其正确,代码也是用C ++编写的。

int RomanToInt(string s){ 
    int len = s.length();
    map<char,int>mp;
    int decimal = 0;
    mp['I'] = 1;mp['V'] = 5;mp['X'] = 10;
    mp['L'] = 50;mp['C'] = 100;mp['D'] = 500;mp['M'] = 1000;
    for(int i = 0; i < len ;i++){
       char cur = s[i],fast = s[i+1];
       int cur_val = mp[cur],fast_val = mp[fast];
       if(cur_val < fast_val){
          decimal = decimal - cur_val;
       }else{
          decimal += cur_val;
       }
    }
    return decimal;
}

答案 20 :(得分:0)

这个怎么样?

int getdec(const string& input)
{
  int sum=0; char prev='%';
  for(int i=(input.length()-1); i>=0; i--)
  {
    if(value(input[i])<sum && (input[i]!=prev))
    {       sum -= value(input[i]);
            prev = input[i];
    }
    else
    {
            sum += value(input[i]);
            prev = input[i];
    }
  }
  return sum;
}

答案 21 :(得分:0)

假设格式良好的罗马数字:

private static int totalValue(String val)
{
    String aux=val.toUpperCase();
    int sum=0, max=aux.length(), i=0;
    while(i<max)
    {
        if ((i+1)<max && valueOf(aux.charAt(i+1))>valueOf(aux.charAt(i)))
        {
            sum+=valueOf(aux.charAt(i+1)) - valueOf(aux.charAt(i));
            i+=2;
        }
        else
        {
            sum+=valueOf(aux.charAt(i));
            i+=1;
        }
    }
    return sum;
}

private static int valueOf(Character c)
{
    char aux = Character.toUpperCase(c);
    switch(aux)
    {
        case 'I':
            return 1;
        case 'V':
            return 5;
        case 'X':
            return 10;
        case 'L':
            return 50;
        case 'C':
            return 100;
        case 'D':
            return 500;
        case 'M':
            return 1000;
        default:
            return 0;
     }
}

答案 22 :(得分:0)

这次转换怎么样?没有开关,根本没有任何情况......

P.S。 :我在bash shell中使用这个脚本

import sys

def RomanToNum(r):

    return {
    'I': 1,
    'V': 5,
    'X': 10,
    'L': 50,
    'C': 100,
    'D': 500,
    'M': 1000,
    }[r]

#
#
#

EOF = "<"
Roman = sys.argv[1].upper().strip()+EOF

num = 0
i = 0

while True:

    this = Roman[i]

    if this == EOF:
        break

    n1 = RomanToNum(this)

    next = Roman[i+1]

    if next == EOF:
        n2 = 0
    else:
        n2 = RomanToNum(next)

    if n1 < n2:
        n1 = -1 * n1

    num = num + n1
    i = i + 1

print num

答案 23 :(得分:0)

        public class RomInt {
    String roman;
    int val;

    void assign(String k)
    {
      roman=k;
    }

    private class Literal
    {
        public char literal;
        public int value;

        public Literal(char literal, int value)
        {
            this.literal = literal;
            this.value = value;
        }
    }

    private final Literal[] ROMAN_LITERALS = new Literal[]
            {
                    new Literal('I', 1),
                    new Literal('V', 5),
                    new Literal('X', 10),
                    new Literal('L', 50),
                    new Literal('C', 100),
                    new Literal('D', 500),
                    new Literal('M', 1000)
            };

    public int getVal(String s) {

       int holdValue=0;

            for (int j = 0; j < ROMAN_LITERALS.length; j++)
            {
                if (s.charAt(0)==ROMAN_LITERALS[j].literal)
                {
                           holdValue=ROMAN_LITERALS[j].value;
                               break;
                }  //if()
            }//for()

      return holdValue;
    }  //getVal()
    public int count()
    {
       int count=0;
       int countA=0;
       int countB=0;
       int lastPosition = 0;
        for(int i = 0 ; i < roman.length(); i++)
        {
          String s1 = roman.substring(i,i+1);
            int a=getVal(s1);
            countA+=a;
        }
        for(int j=1;j<roman.length();j++)
        {
            String s2=  roman.substring(j,j+1);
            String s3=  roman.substring(j-1,j);
            int b=getVal(s2);
            int c=getVal(s3);
            if(b>c)
            {
                countB+=c;
            }
        }
        count=countA-(2*countB);
        return count;
        }


    void disp()
    {

         int result=count();
        System.out.println("Integer equivalent of "+roman+" = " +result);
    }

}  //RomInt---BLC

答案 24 :(得分:0)

由于这里的大多数答案都是用Java编写的,我用C ++发布答案(因为我现在感到很无聊而且没有什么比这更有效率了)但请注意,除非代码错误,否则没有downvotes。 已知问题=不会处理溢出

代码:

#include <unordered_map>
int convert_roman_2_int(string& str)
    {
    int ans = 0;
    if( str.length() == 0 )
        {
        return ans;
        }

    std::unordered_map<char, int> table;
    table['I'] = 1;
    table['V'] = 5;
    table['X'] = 10;
    table['L'] = 50;
    table['C'] = 100;
    table['D'] = 500;
    table['M'] = 1000;

    ans = table[ str[ str.length() - 1 ] ];

    for( int i = str.length() - 2; i >= 0; i--)
        {
        if(table[ str[i] ] < table[ str[i+1] ] )
            {
            ans -= table[ str[i] ];
            }
        else
            {
            ans += table[ str[i] ];
            }
        }

    return ans;
    }

//测试代码

void run_test_cases_convert_roman_to_int()
    {
    string roman = "VIII";
    int r = convert_roman_2_int(roman);
    cout << roman << " in int is " << r << endl << flush;

    roman = "XX";
    r = convert_roman_2_int(roman);
    cout << roman << " in int is " << r << endl << flush;

    roman = "CDX"; //410
    r = convert_roman_2_int(roman);
    cout << roman << " in int is " << r << endl << flush;

    roman = "MCMXC"; //1990
    r = convert_roman_2_int(roman);
    cout << roman << " in int is " << r << endl << flush;

    roman = "MMVIII"; //2008
    r = convert_roman_2_int(roman);
    cout << roman << " in int is " << r << endl << flush;

    roman = "MDCLXVI"; //1666
    r = convert_roman_2_int(roman);
    cout << roman << " in int is " << r << endl << flush;
    }

答案 25 :(得分:0)

这应该有效:

 import java.io.*;
 import java.util.Scanner;

 enum RomanToNumber {
 i(1), v(5), x(10), l(50), c(100); int value;
 RomanToNumber (int p){value = p;}
 int getValue(){return value;}
 }

 public class RomanToInteger {

  public static void main(String[] args){
     RomanToNumber n;

     System.out.println( "Type a valid roman number in lower case" );

     String Str = new String(new Scanner(System.in).nextLine());
     int n1 = 0, theNo = 0, len = Str.length();
     int[] str2No = new int [len];

     for(int i=0; i < len; i++){       
        n = RomanToNumber.valueOf(Str.substring(n1, ++n1));
        str2No[i] = n.getValue();
     }                  

     for(int j = 0; j < (len-1); j++){

        if( str2No[j] >= str2No[j+1] ){ theNo += str2No[j]; }
        else{ theNo -= str2No[j]; }

     }
     System.out.println( theNo += str2No[len-1] );            
     }
  }

答案 26 :(得分:0)

刚开始使用Java,很棒的工作。

    public int getDecimal (String roman) {
        int decimal = 0;
        int romanNumber = 0;
        int prev = 0;
        for (int i = roman.length()-1; i >= 0; i--){
            romanNumber = hashRomans.get(roman.charAt(i));
            if(romanNumber < decimal && romanNumber != prev ){
                decimal -= romanNumber;
                prev = romanNumber;
            } else {
                decimal += romanNumber;
                prev = romanNumber;
            }
        } 
        return decimal;
    }

答案 27 :(得分:0)

//Bet no one has a smaller and easier logic than this........Open CHALLENGE!!!!!!!
import java.io.*;
class Convertion_practical_q2
{
void Decimal()throws IOException //Smaller code for convertion from roman to decimal
{
    DataInputStream in=new DataInputStream(System.in);
    System.out.println("Enter the number");
    String num=in.readLine();
    char pos[]={'0','I','V','X','L','C','D','M'};   
    int l1=7;                           //l1 is size of pos array
    String v[]={"","1","5","10","50","100","500","1000"};
    int l=num.length();
    int p=0,p1=0,sum=0;

    for(int i=l-1;i>=0;i--)
    {
        char ch=num.charAt(i);
        for(int j=1;j<=l1;j++)
        {
            if(ch==pos[j])
            p=j;
        }
        if(p>=p1)
            sum+=Integer.parseInt(v[p]);
        else
            sum-=Integer.parseInt(v[p]);
            //System.out.println("sum ="+sum+"\np="+p+"\np1="+p1);
            p1=p;
    }
    System.out.println(sum);
}
}

答案 28 :(得分:-1)

这是我的......

import java.util.Scanner;
class Solution {

public static void main(String args[]) {

     Scanner sc = new Scanner(System.in);

    String num;

   //  System.out.println("enter the number you want to convert from roman to integer.");

     num = "D";
    System.out.println("length of string is " + num.length());

    System.out.println("the integer number is :" + romanToInt(num) );
}

public static int romanToInt(String s) {

    char I,V, X, L,C, D, M;

    char c1,c3, c2 = s.charAt(0);
   // System.out.println("the c2 is : " + (int)c2);
    int num = 0, num1 = 0;
    int j =0, k = 0, temp = 0;

     if (c2 == 'I') {
            k = (int)c2 - 72;
            System.out.println("k is I" + k);
        } else if(c2 == 'V') {
            k = (int)c2 - 81;
            System.out.println("K is V" + k);
           // return 86 - 81;
        } else if (c2 == 'X') {
             k = (int)c2 - 78;
            System.out.println("K is X" + k);
        } else if (c2 == 'L') {
            k = (int)c2 - 26;
            System.out.println("K is L" + k);
        } else if (c2 == 'C') {
            k = (int)c2 + 33;
            System.out.println("K is C" + k);
        } else if (c2 == 'D') {
             k = (int)c2 + 432;
            System.out.println("K is D" + k);
        } else if ( c2 == 'M') {
             k = (int)c2 + 923;
            System.out.println("K is M" + k);
        }
     if (s.length() == 1){
         num = k;

     } else {
           for(int i = 1; i<= s.length()-1  ; i++) {
        System.out.println("i is : " + i);
         c1 = s.charAt(i);
        if (i == s.length() - 1) {
           temp = 0; 
        } else  {
             c3 = s.charAt(i+1);
             if (c3 == 'I') {

            temp = (int)c3 - 72;
            System.out.println("temp is I " + temp);
        } else if(c3 == 'V') {
            temp = (int)c3 - 81;
            System.out.println("temp is I " + temp);
           // return 86 - 81;
        } else if (c3 == 'X') {
             temp = (int)c3 - 78;
             System.out.println("temp is I " + temp);
        } else if (c3 == 'L') {
            temp = (int)c3 - 26;
             System.out.println("temp is I " + temp);
        } else if (c3 == 'C') {
            temp = (int)c3 + 33;
            System.out.println("temp is I " + temp);
        } else if (c3 == 'D') {
             temp = (int)c3 + 432;
             System.out.println("temp is I " + temp);
        } else if ( c3 == 'M') {
             temp = (int)c3 + 923;
             System.out.println("temp is I " + temp);
        }
        }


        if (c1 == 'I') {

            j = (int)c1 - 72;
            System.out.println("j is I " + j);
        } else if(c1 == 'V') {
            j = (int)c1 - 81;
            System.out.println("j is V " + j);
           // return 86 - 81;
        } else if (c1 == 'X') {
             j = (int)c1 - 78;
            System.out.println("j is X " + j);
        } else if (c1 == 'L') {
            j = (int)c1 - 26;
            System.out.println("j is L " + j);
        } else if (c1 == 'C') {
            j = (int)c1 + 33;
            System.out.println("j is C " + j);
        } else if (c1 == 'D') {
             j = (int)c1 + 432;
            System.out.println("j is D " + j);
        } else if ( c1 == 'M') {
             j = (int)c1 + 923;
            System.out.println("j is M " + j);
        }

        if ( k < j && j>temp ) {
           k = j - k ;
          num = num + k;


        } else if (j==k || j<k || j<temp){

               num = num + k ; 
           //   k = j;
        }

        if (j>k ) {
            k = temp;
            i += 1;

            if (i == s.length()-1) {
                num = num + k;
            }
        } else {
            k = j;
            if (i == s.length()-1) {
                num = num + k;
            }

        }



     }

  }   

    return num;                         
   }

}