Soru Romen Rakamlarını Ondalıklara Dönüştürme


Çoğu Romen rakamını uygun ondalık değerine dönüştürmek için kodumu almayı başardım. Ancak bazı istisnai durumlar için işe yaramıyor. Örnek : XCIX = 99 ama kodum basılıyor 109.

İşte benim kodum.

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

33
2018-01-31 01:08


Menşei


Bu klasik bir ev ödevi sorusu. Bu gerçekten ev ödevi ise, lütfen sorunuzu bu şekilde etiketleyin. - BalusC
Evet, bu senin kodun. Sorunuz nedir? - nachito
@nachito: Bahse girerim neden örnek olduğunu merak ediyor XCIX döner 109 yerine 99. - BalusC
Nedenini biliyorum çünkü hem 'IX' hem de 'XC' içeriyor ... ama bunu nasıl düzelteceğimi bilemiyorum .. - Daniel Cook
Ödev etiketi kullanımdan kaldırıldı - RNJ


Cevaplar:


Tersine hareket ederseniz iyi olur.

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

52
2018-01-31 01:31



teşekkür ederim, sihir gibi çalıştı: D - Daniel Cook
@DanielFarmer - bunun aslında sihir olmadığını ve ev ödevi işe yaradığını öğrenmelisiniz. - prelic
IIX bu kod üzerinde çalışacaktı. Ve bu geçersiz bir sayı. - David Anderson
ABC de çalışır, 100 verir. - sgowd
IIXX'i girdi olarak verirsek, çıktı olarak 20 alırım, bu da yanlıştır. Bir hata atmamalı. - John Constantine


Bunu deneyin - Bu basit ve kompakttır ve oldukça sorunsuz çalışır:

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

37
2017-07-08 19:21



Bir UltraEdit betiğinde JavaScript'e dönüştürülmüş bu çok küçük kodu kullandım Romen rakamlarını Arapça ondalık tamsayıya dönüştür. - Mofi
Bu özyinelemeyi de kullandım. İfadelerden çok daha kolay - Jethro
Harika çözüm. Ancak bir tidbit: Bir harf art arda 3 defadan fazla tekrarlanamaz ve sadece 10'luk güçler tekrarlanabilir. Algo'nuz IIII'yi 4'e dönüştürür; ama, onaylamanın kullanıcıya bırakılacağını varsaydığını farz ettim! - LevinsonTechnologies
Doğrulama adımı iyi olurdu, aksi halde geçersiz giriş olan "IVX" için 14 basarsınız. - damluar
Bu bir java kodu, bu bana C gibi geliyor! - humazed


hashın böyle bir şey olduğunu varsayarak

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

daha sonra mantık sağdan sola doğru gidiyor

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

22
2017-08-20 18:15



Çok güzel ve özlü bir uygulama - TheDareDevil
İyi uygulama, ve bir gün eğer çocuklar bir milyonu temsil edecek bir mektup seçmeye karar verirlerse uzatmak kolaydır ;-) ;-) - jpo38
Bu, örneğin, IIX için çalışmıyor - Khanh Nguyen
IIX geçerli bir sembol değil -> Herhangi bir büyük-değer sembolünden sadece bir küçük-değer sembolü çıkarılabilir. 8 VIII olarak temsil edilmektedir - Didac Montero


IX'de 2'yi azaltma mantığınızı takiben, CM üzerinde XC 200'de 20'yi azaltmalısınız.


4
2018-01-31 01:18



Bu istenen sonucu almaz. - Ravindra Gullapalli


Daha az kod, daha verimli. Daha net değil, üzgünüm!

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

3
2018-03-23 19:31



Bu düşük McCabe karmaşıklığı ile matematiksel bir sürümüdür. - Edworld
Bunun eski olduğunu biliyorum ama bu kod parçasının bir açıklamasını bana verebilir misin diye merak ediyordum? Ya da belki bir makaleye bir link?


Doğrulama adımı ve çevrimiçi test ile engelleyici + özyineli çözümler

Kullanışlı olmayan hesaplamaları önlemek ve romen rakamları formatının doğru olduğundan emin olmak için, girişi düzenli bir ifadeyle kontrol etmeliyiz.

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

Yıkıcı çözüm 

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

çevrimiçi dene | Yorumlar / açıklamalar çevrimiçi ile optimize edilmiş versiyonu deneyin


GÜNCELLEŞTİRME: İşte bu adımdan iki akıllı tekrarlayıcı teklifim onaylama adımı ekleyerek çözdüm

Özyineli çözüm 1 (orijinal cevap)

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

çevrimiçi dene

Yinelemeli çözüm 2 (orijinal cevap)

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

çevrimiçi dene


3
2017-10-15 23:27





Aşağıdaki kodu kontrol edebilirsiniz. Bu kod tüm durumlarda çalışmalıdır. Ayrıca boş veya boş giriş ve hatalı girişleri de kontrol eder (ABXI ile denediğinizi varsayalım)

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

}

2
2018-05-24 12:02





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

2
2018-03-23 14:05



Lütfen bu 3 yıllık sorunun diğer 14 cevabına ne eklediğini açıklayın ... - fancyPants
Sorunu matematiksel olarak çözmek için başka bir yoldur. İstihbarat ekler. Neden cevabı negativ? Sadece sevmediğin için mi? Yoksa anlamadın mı? - André Schonrock
Reddetmedi. Sadece yorumumu bıraktım sadece bir kod sadece uzun yıllar sonra cevap ver ... çünkü, sadece cevaplar genellikle değil, er, vesile kadar değerlidir. - fancyPants
Yani lütfen afedersiniz. Bu sitede yeniim ve olumlu bir ilişkide bulunmak istiyorum, ona karşı hiçbir şey, Brezilya'lıyım ama Alman kökenli. rs - André Schonrock


Bu soruna 3 farklı senaryo ile bakalım

1. Senaryo:

Aşağıdaki gibi bir model gördüğümüzde

'IIIIII' or 'XXXXX'  or 'CCCC'

tüm karakterler aynı olduğunda: Kalıptaki her karakterin değerini ekliyoruz

'IIIIII' gives us '6'

'XXXXX' gives us '50'

'CCCC' gives us '400'

2. Senaryo:

2 ardışık karakter farklı gördüğümüzde, ilk değer küçük olduğunda o zaman 2.

'IX' or 'XC'

İlk olarak ikinci değerinden çıkartıyoruz.

second:'X' gives us '10'

first: 'I' gives us '1'

second  - first :  10 - 1 = 9

3. Senaryo:

Birincisi değerde daha büyük olan ardışık 2 karakter gördüğümüzde

'XI' or 'CX'

Birinci ve ikinci olarak ekliyoruz, ör.

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

Şimdi bunu tekrarlı olarak yaparsak sonucu bulabiliriz. İşte java uygulaması:

//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']; 
}

1
2017-07-11 13:13



Senaryo 1 geçerli bir Romen Rakamı değil ... Daha yüksek bir char ve en yüksek MOST 1 ardışık aynı chars sonra MOST 3 ardışık aynı chars olabilir. - adinutzyc21