java - romano - numeros arabes conversor
Conversión de números romanos a decimal (26)
Logré obtener mi código para convertir la mayoría de los números romanos a su valor decimal apropiado. Pero no funciona en algunos casos excepcionales. Ejemplo: XCIX
= 99
pero mi código imprime 109
.
Aquí está mi código.
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;
}
Imperativo + soluciones recursivas con paso de validación y pruebas en línea
Para evitar cálculos inútiles y asegurarse de que el formato de los números romanos sea el correcto, necesitamos verificar la entrada con una expresión regular.
String regex = "^(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$";
- Explicación de la expresión regular en detalles
- Explicación de los símbolos de expresión regular utilizados
- Las diferencias entre las funciones de expresiones regulares coinciden () y find ()
- ¿Por qué MMMCMXCIX (= 3999) es el valor máximo con notación de números romanos estándar?
Solución imperativa
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;
}
prueba en línea | prueba la versión optimizada con comentarios / explicación en línea
ACTUALIZACIÓN : aquí hay dos propuestas recursivas ingeniosas de este hilo que resolví agregando paso de validación
Solución recursiva 1 ( respuesta original )
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);
}
}
Solución recursiva 2 ( respuesta original )
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);
}
}
¿Qué hay de esta conversión? sin interruptor, sin estuche ...
PD: utilizo este script desde un shell bash
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
¿Qué tal esto?
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;
}
Acabo de hacerlo funcionar en Java, buen trabajo chicos.
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;
}
Como la mayoría de las respuestas aquí están en Java, estoy publicando la respuesta en C ++ (ya que estoy aburrido en este momento y no tengo nada más productivo que hacer :) Pero, por favor, no hay votaciones, excepto si el código es incorrecto. Known-issues = no manejará el desbordamiento
Código:
#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;
}
// código de prueba
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;
}
Encuentro que el siguiente enfoque es muy intuitivo:
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);
}
Esta es una variación modesta del algoritmo recursivo sugerido por 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");
}
Utiliza menos de 10 líneas de código efectivas.
Esta solución scala
podría ser útil:
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))
}
}
Esto debería funcionar:
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] );
}
}
Menos código, más eficiente. No tan claro, lo siento!
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);
}
Pruebe esto: es simple y compacto y funciona sin problemas:
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");
}
Será bueno si atraviesas en reversa.
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");
}
}
Siguiendo su lógica de reducir 2 en IX, debe reducir 20 en XC 200 en CM y así sucesivamente.
Solución usando recursividad de cola:
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;
}
}
Pruebas:
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));
}
}
Suponiendo números romanos bien formados:
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;
}
}
Usted puede verificar el siguiente código. Este código debería funcionar en todos los casos. También verifica la entrada nula o vacía y la entrada defectuosa (digamos que lo intentó con 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"));
}
}
Veamos este problema con 3 escenarios diferentes
Escenario 1:
Cuando vemos un patrón como el siguiente
''IIIIII'' or ''XXXXX'' or ''CCCC''
donde todos los caracteres son iguales: agregamos el valor de cada carácter en el patrón
''IIIIII'' gives us ''6''
''XXXXX'' gives us ''50''
''CCCC'' gives us ''400''
Escenario 2:
Cuando vemos 2 caracteres consecutivos diferentes donde el primero es menor en valor, entonces el segundo
''IX'' or ''XC''
Restamos el valor de primero de segundo ejemplo
second:''X'' gives us ''10''
first: ''I'' gives us ''1''
second - first : 10 - 1 = 9
Escenario 3:
Cuando vemos un 2 caracteres consecutivos diferentes donde el primero es mayor en valor, entonces el segundo
''XI'' or ''CX''
Añadimos primero y segundo ejemplo
second:''I'' gives us ''10''
first: ''X'' gives us ''1''
first + second : 10 + 1 = 11
Ahora podemos encontrar el resultado si hacemos esto recursivamente. Aquí está la implementación de 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''];
}
Versión completa con comprobación de errores y prueba todos los valores válidos en ambas direcciones (y algunos casos no válidos).
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;
}
}
Salida
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
asumiendo que el hash se parece a esto
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);
entonces la lógica se vuelve bastante simple yendo por el dígito de derecha a izquierda
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;
}
esta es una implementación muy básica de lo que pidió y que funciona para todos los casos de prueba. Si encuentra algo incorrecto que lo mencione, intentaré corregirlo también el código está en 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;
}
Aquí está mi ...
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;
}
}
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
// 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)));
}
//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);
}
}
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;
}
}
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;
}