fork(1) download
  1. /* package whatever; // don't place package name! */
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import java.util.regex.Matcher;
  5. import java.util.regex.Pattern;
  6.  
  7. /**
  8.  * Optimizations:
  9.  * - Creates a map to get each roman numeral decimal value with O(1) complexity
  10.  * - All Regex compiled only once
  11.  * - Minimum code run each time after initialization
  12.  */
  13.  
  14. /* Name of the class has to be "Main" only if the class is public. */
  15. class RomanToDecimalConverter {
  16. public static void main (String[] args) {
  17. printRomanToDecimal("XCIX");
  18. printRomanToDecimal("MMMCMXCIX");
  19.  
  20. //error cases
  21. printRomanToDecimal("IIX");
  22. printRomanToDecimal("IIXX");
  23. printRomanToDecimal("ABC");
  24. printRomanToDecimal("IVX");
  25. }
  26.  
  27. private static void printRomanToDecimal(String s) {
  28. int decimal = convert(s);
  29. String output = decimal != -1 ? ""+decimal : "Invalid roman numerals";
  30. System.out.println(s + ": " + output);
  31. }
  32.  
  33. private static final Map<String, Integer> ROMAN_NUMERALS_TO_DECIMAL_MAP;
  34.  
  35. static {
  36. //init the correspondence map <RomanNumeral, DecimalValue> when the class is loaded
  37. ROMAN_NUMERALS_TO_DECIMAL_MAP = new HashMap<>();
  38.  
  39. String[] romanNumerals = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
  40. int[] decimalValues = {1000,900,500,400,100,90,50,40,10,9,5,4,1};
  41.  
  42. //let's map each roman numeral to its decimal value
  43. for (int i = 0; i < decimalValues.length; i++) {
  44. ROMAN_NUMERALS_TO_DECIMAL_MAP.put(romanNumerals[i], decimalValues[i]);
  45. }
  46. }
  47.  
  48. //checks roman numerals format (max number is 3999 = MMMCMXCIX)
  49. //@see http://w...content-available-to-author-only...e.ro/reguli_scriere_cifre_numere_romane.php?lang=en
  50. private static final Pattern CHECK_ROMAN_NUMERALS_FORMAT_REGEX =
  51. Pattern.compile("^(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$");
  52.  
  53. //we need this compiled regex to match each roman numeral one by one
  54. //from left to right from the highest to the lowest decimal value
  55. private static final Pattern FIND_ROMAN_NUMERALS_ONE_BY_ONE_REGEX =
  56. Pattern.compile("M|CM|D|CD|C|XC|L|XL|X|IX|V|IV|I");
  57.  
  58. private static boolean containsValidRomanNumerals(String s) {
  59. return !(s == null || s.isEmpty() || !CHECK_ROMAN_NUMERALS_FORMAT_REGEX.matcher(s).matches());
  60. }
  61.  
  62. /**
  63.   * Converts roman numerals to their decimal value
  64.   * @param s String containing roman numerals
  65.   * @return decimal value corresponding to the roman numerals input
  66.   */
  67. public static int convert(String s) {
  68. if (!containsValidRomanNumerals(s)) return -1;
  69.  
  70. final Matcher matcher = FIND_ROMAN_NUMERALS_ONE_BY_ONE_REGEX.matcher(s);
  71.  
  72. int sum = 0;
  73. //every time we find a roman numeral...
  74. while (matcher.find()) {
  75. //...let's add its decimal value to the sum
  76. sum += ROMAN_NUMERALS_TO_DECIMAL_MAP.get(matcher.group(0));
  77. }
  78.  
  79. return sum;
  80. }
  81. }
Success #stdin #stdout 0.12s 320576KB
stdin
Standard input is empty
stdout
XCIX: 99
MMMCMXCIX: 3999
IIX: Invalid roman numerals
IIXX: Invalid roman numerals
ABC: Invalid roman numerals
IVX: Invalid roman numerals