将整数转换为罗马数字-Java

这是一个我做不来的家庭作业。

我需要使用一个方法制作一个整数到罗马数字的转换器。之后,我必须用这个程序用罗马数字写出1到3999,所以不再需要硬编码。我下面的代码是非常基本的; 它是一个基本的 I/O 循环,在使用我们在课堂上为 getIntegerFromUser制作的包时,它提供了一种退出的方法。

有没有一种方法可以将值赋给 String,然后在调用该方法时将它们相加?

更新: 我从我的教授那里得到了一些伪代码来帮助我,虽然我明白他想说什么,但是我在使用 if时遇到了一些麻烦。我将需要许多,许多 if语句,以便我的转换器将正确处理罗马数字格式或有一种方式,我可以更有效地做到这一点?我更新了代码以反映占位符方法。

更新(2012年10月28日) : 我让它工作了,以下是我最后使用的:

public static String IntegerToRomanNumeral(int input) {
if (input < 1 || input > 3999)
return "Invalid Roman Number Value";
String s = "";
while (input >= 1000) {
s += "M";
input -= 1000;        }
while (input >= 900) {
s += "CM";
input -= 900;
}
while (input >= 500) {
s += "D";
input -= 500;
}
while (input >= 400) {
s += "CD";
input -= 400;
}
while (input >= 100) {
s += "C";
input -= 100;
}
while (input >= 90) {
s += "XC";
input -= 90;
}
while (input >= 50) {
s += "L";
input -= 50;
}
while (input >= 40) {
s += "XL";
input -= 40;
}
while (input >= 10) {
s += "X";
input -= 10;
}
while (input >= 9) {
s += "IX";
input -= 9;
}
while (input >= 5) {
s += "V";
input -= 5;
}
while (input >= 4) {
s += "IV";
input -= 4;
}
while (input >= 1) {
s += "I";
input -= 1;
}
return s;
}
267164 次浏览

我很好奇这事会怎么收场。我会开始研究1,2,3,5,6,7,8,9,10到 I,II,III,IV,V,VI,VII,IX,X 的映射... 然后你可能会研究罗马数字的规则: I,II,III 是由串联产生的 V、 X、 L、 C、 D 和 M 是5、10、50、100、500和1000的符号 罗马人认为,他们可以节省空间写数字,而不是写,例如三四用四(意思是: 5减1...) 你可能需要研究这些规则,例如在 http://en.wikipedia.org/wiki/Roman_numerals,并在代码中捕获它们,例如在一个类“ RomanNumbers”中 如果你想作弊,你可以点击这个链接: http://www.moxlotus.Alternatifs.eu/program-Converter.html rel = “ nofollow”> http://www.moxlotus.alternatifs.eu/programmation-converter.html

Java Notes 6.0网站:

      /**
* An object of type RomanNumeral is an integer between 1 and 3999.  It can
* be constructed either from an integer or from a string that represents
* a Roman numeral in this range.  The function toString() will return a
* standardized Roman numeral representation of the number.  The function
* toInt() will return the number as a value of type int.
*/
public class RomanNumeral {


private final int num;   // The number represented by this Roman numeral.


/* The following arrays are used by the toString() function to construct
the standard Roman numeral representation of the number.  For each i,
the number numbers[i] is represented by the corresponding string, letters[i].
*/


private static int[]    numbers = { 1000,  900,  500,  400,  100,   90,
50,   40,   10,    9,    5,    4,    1 };


private static String[] letters = { "M",  "CM",  "D",  "CD", "C",  "XC",
"L",  "XL",  "X",  "IX", "V",  "IV", "I" };


/**
* Constructor.  Creates the Roman number with the int value specified
* by the parameter.  Throws a NumberFormatException if arabic is
* not in the range 1 to 3999 inclusive.
*/
public RomanNumeral(int arabic) {
if (arabic < 1)
throw new NumberFormatException("Value of RomanNumeral must be positive.");
if (arabic > 3999)
throw new NumberFormatException("Value of RomanNumeral must be 3999 or less.");
num = arabic;
}




/*
* Constructor.  Creates the Roman number with the given representation.
* For example, RomanNumeral("xvii") is 17.  If the parameter is not a
* legal Roman numeral, a NumberFormatException is thrown.  Both upper and
* lower case letters are allowed.
*/
public RomanNumeral(String roman) {


if (roman.length() == 0)
throw new NumberFormatException("An empty string does not define a Roman numeral.");


roman = roman.toUpperCase();  // Convert to upper case letters.


int i = 0;       // A position in the string, roman;
int arabic = 0;  // Arabic numeral equivalent of the part of the string that has
//    been converted so far.


while (i < roman.length()) {


char letter = roman.charAt(i);        // Letter at current position in string.
int number = letterToNumber(letter);  // Numerical equivalent of letter.


i++;  // Move on to next position in the string


if (i == roman.length()) {
// There is no letter in the string following the one we have just processed.
// So just add the number corresponding to the single letter to arabic.
arabic += number;
}
else {
// Look at the next letter in the string.  If it has a larger Roman numeral
// equivalent than number, then the two letters are counted together as
// a Roman numeral with value (nextNumber - number).
int nextNumber = letterToNumber(roman.charAt(i));
if (nextNumber > number) {
// Combine the two letters to get one value, and move on to next position in string.
arabic += (nextNumber - number);
i++;
}
else {
// Don't combine the letters.  Just add the value of the one letter onto the number.
arabic += number;
}
}


}  // end while


if (arabic > 3999)
throw new NumberFormatException("Roman numeral must have value 3999 or less.");


num = arabic;


} // end constructor




/**
* Find the integer value of letter considered as a Roman numeral.  Throws
* NumberFormatException if letter is not a legal Roman numeral.  The letter
* must be upper case.
*/
private int letterToNumber(char letter) {
switch (letter) {
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:   throw new NumberFormatException(
"Illegal character \"" + letter + "\" in Roman numeral");
}
}




/**
* Return the standard representation of this Roman numeral.
*/
public String toString() {
String roman = "";  // The roman numeral.
int N = num;        // N represents the part of num that still has
//   to be converted to Roman numeral representation.
for (int i = 0; i < numbers.length; i++) {
while (N >= numbers[i]) {
roman += letters[i];
N -= numbers[i];
}
}
return roman;
}




/**
* Return the value of this Roman numeral as an int.
*/
public int toInt() {
return num;
}




}
String convert(int i){


String ones = "";
String tens = "";
String hundreds = "";
String thousands = "";
String result ;


boolean error = false;


Vector v = new Vector();


//assign passed integer to temporary value temp
int temp=i;


//flags an error if number is greater than 3999
if (temp >=4000) {
error = true;
}


/*loops while temp can no more be divided by 10.
Lets say i = 3254, then temp is also 3254 at line 14.


3254
3254/10 = 25    /   \ 3254%10 = 4
/     \
now temp = 25       325     4  - here 4 is added to the vector v's 0th index.
/ \
now temp = 32     32   5  - here 5 is added to the vector v's 1st index.
/  \
now temp = 3    3    2  - here 2 is added to the vector v's 2nd index, and loop exits
/ \        since temp/10 = 0
0   3  - here 3 is not added to the vector v's 3rd index as loop exits when
temp/10 = 0.




*/
while (temp/10 != 0) {
if (temp / 10 != 0 && temp <4000) {
v.add(temp%10);
temp = temp / 10;
}else {
break;
}
}


//therefore you have to add temp one last time to the vector
v.add(temp);


//as in the example now you have 4,5,2,3 respectively in v's 0,1,2,3 indices.




for (int j = 0; j < v.size(); j++) {


//you see that v's 0th index has number of ones. So make them roman ones here.
if (j==0) {
switch (v.get(0).toString()){
case "0" : ones = ""; break;
case "1" : ones = "I"; break;
case "2" : ones = "II"; break;
case "3" : ones = "III"; break;
case "4" : ones = "IV"; break;
case "5" : ones = "V"; break;
case "6" : ones = "VI"; break;
case "7" : ones = "VII"; break;
case "8" : ones = "VIII"; break;
case "9" : ones = "IX"; break;
}




//in the second iteration of the loop (when j==1)
//index 1 of v is checked. Now you understand that v's 1st index
//has the tens
} else if (j == 1) {
switch (v.get(1).toString()){
case "0" : tens = ""; break;
case "1" : tens = "X"; break;
case "2" : tens = "XX"; break;
case "3" : tens = "XXX"; break;
case "4" : tens = "XL"; break;
case "5" : tens = "L"; break;
case "6" : tens = "LX"; break;
case "7" : tens = "LXX"; break;
case "8" : tens = "LXXX"; break;
case "9" : tens = "XC"; break;
}
} else if(j == 2){  //and hundreds
switch (v.get(2).toString()){
case "0" : hundreds = ""; break;
case "1" : hundreds = "C"; break;
case "2" : hundreds = "CC"; break;
case "3" : hundreds = "CCC"; break;
case "4" : hundreds = "CD"; break;
case "5" : hundreds = "D"; break;
case "6" : hundreds = "DC"; break;
case "7" : hundreds = "DCC"; break;
case "8" : hundreds = "DCCC"; break;
case "9" : hundreds = "CM"; break;
}
}   else if(j == 3){ //and finally thousands.
switch (v.get(3).toString()){
case "0" : thousands = ""; break;
case "1" : thousands = "M"; break;
case "2" : thousands = "MM"; break;
case "3" : thousands = "MMM"; break;


}
}
}






if (error) {
result = "Error!";
}else{
result = thousands + hundreds + tens + ones;
}


return result;


}

使用这些库:

import java.util.LinkedHashMap;
import java.util.Map;

密码:

  public static String RomanNumerals(int Int) {
LinkedHashMap<String, Integer> roman_numerals = new LinkedHashMap<String, Integer>();
roman_numerals.put("M", 1000);
roman_numerals.put("CM", 900);
roman_numerals.put("D", 500);
roman_numerals.put("CD", 400);
roman_numerals.put("C", 100);
roman_numerals.put("XC", 90);
roman_numerals.put("L", 50);
roman_numerals.put("XL", 40);
roman_numerals.put("X", 10);
roman_numerals.put("IX", 9);
roman_numerals.put("V", 5);
roman_numerals.put("IV", 4);
roman_numerals.put("I", 1);
String res = "";
for(Map.Entry<String, Integer> entry : roman_numerals.entrySet()){
int matches = Int/entry.getValue();
res += repeat(entry.getKey(), matches);
Int = Int % entry.getValue();
}
return res;
}
public static String repeat(String s, int n) {
if(s == null) {
return null;
}
final StringBuilder sb = new StringBuilder();
for(int i = 0; i < n; i++) {
sb.append(s);
}
return sb.toString();
}

测试代码:

  for (int i = 1;i<256;i++) {
System.out.println("i="+i+" -> "+RomanNumerals(i));
}

输出:

  i=1 -> I
i=2 -> II
i=3 -> III
i=4 -> IV
i=5 -> V
i=6 -> VI
i=7 -> VII
i=8 -> VIII
i=9 -> IX
i=10 -> X
i=11 -> XI
i=12 -> XII
i=13 -> XIII
i=14 -> XIV
i=15 -> XV
i=16 -> XVI
i=17 -> XVII
i=18 -> XVIII
i=19 -> XIX
i=20 -> XX
i=21 -> XXI
i=22 -> XXII
i=23 -> XXIII
i=24 -> XXIV
i=25 -> XXV
i=26 -> XXVI
i=27 -> XXVII
i=28 -> XXVIII
i=29 -> XXIX
i=30 -> XXX
i=31 -> XXXI
i=32 -> XXXII
i=33 -> XXXIII
i=34 -> XXXIV
i=35 -> XXXV
i=36 -> XXXVI
i=37 -> XXXVII
i=38 -> XXXVIII
i=39 -> XXXIX
i=40 -> XL
i=41 -> XLI
i=42 -> XLII
i=43 -> XLIII
i=44 -> XLIV
i=45 -> XLV
i=46 -> XLVI
i=47 -> XLVII
i=48 -> XLVIII
i=49 -> XLIX
i=50 -> L
i=51 -> LI
i=52 -> LII
i=53 -> LIII
i=54 -> LIV
i=55 -> LV
i=56 -> LVI
i=57 -> LVII
i=58 -> LVIII
i=59 -> LIX
i=60 -> LX
i=61 -> LXI
i=62 -> LXII
i=63 -> LXIII
i=64 -> LXIV
i=65 -> LXV
i=66 -> LXVI
i=67 -> LXVII
i=68 -> LXVIII
i=69 -> LXIX
i=70 -> LXX
i=71 -> LXXI
i=72 -> LXXII
i=73 -> LXXIII
i=74 -> LXXIV
i=75 -> LXXV
i=76 -> LXXVI
i=77 -> LXXVII
i=78 -> LXXVIII
i=79 -> LXXIX
i=80 -> LXXX
i=81 -> LXXXI
i=82 -> LXXXII
i=83 -> LXXXIII
i=84 -> LXXXIV
i=85 -> LXXXV
i=86 -> LXXXVI
i=87 -> LXXXVII
i=88 -> LXXXVIII
i=89 -> LXXXIX
i=90 -> XC
i=91 -> XCI
i=92 -> XCII
i=93 -> XCIII
i=94 -> XCIV
i=95 -> XCV
i=96 -> XCVI
i=97 -> XCVII
i=98 -> XCVIII
i=99 -> XCIX
i=100 -> C
i=101 -> CI
i=102 -> CII
i=103 -> CIII
i=104 -> CIV
i=105 -> CV
i=106 -> CVI
i=107 -> CVII
i=108 -> CVIII
i=109 -> CIX
i=110 -> CX
i=111 -> CXI
i=112 -> CXII
i=113 -> CXIII
i=114 -> CXIV
i=115 -> CXV
i=116 -> CXVI
i=117 -> CXVII
i=118 -> CXVIII
i=119 -> CXIX
i=120 -> CXX
i=121 -> CXXI
i=122 -> CXXII
i=123 -> CXXIII
i=124 -> CXXIV
i=125 -> CXXV
i=126 -> CXXVI
i=127 -> CXXVII
i=128 -> CXXVIII
i=129 -> CXXIX
i=130 -> CXXX
i=131 -> CXXXI
i=132 -> CXXXII
i=133 -> CXXXIII
i=134 -> CXXXIV
i=135 -> CXXXV
i=136 -> CXXXVI
i=137 -> CXXXVII
i=138 -> CXXXVIII
i=139 -> CXXXIX
i=140 -> CXL
i=141 -> CXLI
i=142 -> CXLII
i=143 -> CXLIII
i=144 -> CXLIV
i=145 -> CXLV
i=146 -> CXLVI
i=147 -> CXLVII
i=148 -> CXLVIII
i=149 -> CXLIX
i=150 -> CL
i=151 -> CLI
i=152 -> CLII
i=153 -> CLIII
i=154 -> CLIV
i=155 -> CLV
i=156 -> CLVI
i=157 -> CLVII
i=158 -> CLVIII
i=159 -> CLIX
i=160 -> CLX
i=161 -> CLXI
i=162 -> CLXII
i=163 -> CLXIII
i=164 -> CLXIV
i=165 -> CLXV
i=166 -> CLXVI
i=167 -> CLXVII
i=168 -> CLXVIII
i=169 -> CLXIX
i=170 -> CLXX
i=171 -> CLXXI
i=172 -> CLXXII
i=173 -> CLXXIII
i=174 -> CLXXIV
i=175 -> CLXXV
i=176 -> CLXXVI
i=177 -> CLXXVII
i=178 -> CLXXVIII
i=179 -> CLXXIX
i=180 -> CLXXX
i=181 -> CLXXXI
i=182 -> CLXXXII
i=183 -> CLXXXIII
i=184 -> CLXXXIV
i=185 -> CLXXXV
i=186 -> CLXXXVI
i=187 -> CLXXXVII
i=188 -> CLXXXVIII
i=189 -> CLXXXIX
i=190 -> CXC
i=191 -> CXCI
i=192 -> CXCII
i=193 -> CXCIII
i=194 -> CXCIV
i=195 -> CXCV
i=196 -> CXCVI
i=197 -> CXCVII
i=198 -> CXCVIII
i=199 -> CXCIX
i=200 -> CC
i=201 -> CCI
i=202 -> CCII
i=203 -> CCIII
i=204 -> CCIV
i=205 -> CCV
i=206 -> CCVI
i=207 -> CCVII
i=208 -> CCVIII
i=209 -> CCIX
i=210 -> CCX
i=211 -> CCXI
i=212 -> CCXII
i=213 -> CCXIII
i=214 -> CCXIV
i=215 -> CCXV
i=216 -> CCXVI
i=217 -> CCXVII
i=218 -> CCXVIII
i=219 -> CCXIX
i=220 -> CCXX
i=221 -> CCXXI
i=222 -> CCXXII
i=223 -> CCXXIII
i=224 -> CCXXIV
i=225 -> CCXXV
i=226 -> CCXXVI
i=227 -> CCXXVII
i=228 -> CCXXVIII
i=229 -> CCXXIX
i=230 -> CCXXX
i=231 -> CCXXXI
i=232 -> CCXXXII
i=233 -> CCXXXIII
i=234 -> CCXXXIV
i=235 -> CCXXXV
i=236 -> CCXXXVI
i=237 -> CCXXXVII
i=238 -> CCXXXVIII
i=239 -> CCXXXIX
i=240 -> CCXL
i=241 -> CCXLI
i=242 -> CCXLII
i=243 -> CCXLIII
i=244 -> CCXLIV
i=245 -> CCXLV
i=246 -> CCXLVI
i=247 -> CCXLVII
i=248 -> CCXLVIII
i=249 -> CCXLIX
i=250 -> CCL
i=251 -> CCLI
i=252 -> CCLII
i=253 -> CCLIII
i=254 -> CCLIV
i=255 -> CCLV

使用 Java树木地图和递归的简洁实现:

import java.util.TreeMap;


public class RomanNumber {


private final static TreeMap<Integer, String> map = new TreeMap<Integer, String>();


static {


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


}


public final static String toRoman(int number) {
int l =  map.floorKey(number);
if ( number == l ) {
return map.get(number);
}
return map.get(l) + toRoman(number-l);
}


}

测试:

public void testRomanConversion() {


for (int i = 1; i<= 100; i++) {
System.out.println(i+"\t =\t "+RomanNumber.toRoman(i));
}


}

我的解决方案是函数 getRoman:

public  String getRoman(int number) {


String riman[] = {"M","XM","CM","D","XD","CD","C","XC","L","XL","X","IX","V","IV","I"};
int arab[] = {1000, 990, 900, 500, 490, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
StringBuilder result = new StringBuilder();
int i = 0;
while (number > 0 || arab.length == (i - 1)) {
while ((number - arab[i]) >= 0) {
number -= arab[i];
result.append(riman[i]);
}
i++;
}
return result.toString();
}

在这里看到一些答案后,我不得不发布这个。我认为我的算法是最容易理解的,即使在相对较大的范围内,性能损失也不重要。我也遵守标准化的编码惯例,而不是这里的一些用户。

平均转换时间: 0.05 ms (基于将所有数字1-3999转换并除以3999)

public static String getRomanNumeral(int arabicNumber) {


if (arabicNumber > 0 && arabicNumber < 4000) {


final LinkedHashMap<Integer, String> numberLimits =
new LinkedHashMap<>();


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


String romanNumeral = "";


while (arabicNumber > 0) {
int highestFound = 0;
for (Map.Entry<Integer, String> current : numberLimits.entrySet()){
if (current.getKey() <= arabicNumber) {
highestFound = current.getKey();
}
}
romanNumeral += numberLimits.get(highestFound);
arabicNumber -= highestFound;
}


return romanNumeral;


} else {
throw new UnsupportedOperationException(arabicNumber
+ " is not a valid Roman numeral.");
}
}

首先,您必须考虑到罗马数字只在 < 1-4000的区间内) ,但是这可以通过一个简单的 if 和一个抛出的异常来解决。然后,您可以尝试在给定的整数中找到最大的集合罗马数字,如果找到,则从原始数字中减去该集合罗马数字,并将其添加到结果中。重复使用新获得的数字,直到达到零。

基于 OP 自身解决方案的替代解决方案,利用 enum。此外,还包括解析器和往返测试。

public class RomanNumber {
public enum Digit {
M(1000, 3),
CM(900, 1),
D(500, 1),
CD(400, 1),
C(100, 3),
XC(90, 1),
L(50, 1),
XL(40, 1),
X(10, 3),
IX(9, 1),
V(5, 1),
IV(4, 1),
I(1, 3);


public final int value;
public final String symbol = name();
public final int maxArity;


private Digit(int value, int maxArity) {
this.value = value;
this.maxArity = maxArity;
}
}


private static final Digit[] DIGITS = Digit.values();


public static String of(int number) {
if (number < 1 || 3999 < number) {
throw new IllegalArgumentException(String.format(
"Roman numbers are only defined for numbers between 1 and 3999 (%d was given)",
number
));
}


StringBuilder sb = new StringBuilder();
for (Digit digit : DIGITS) {
int value = digit.value;
String symbol = digit.symbol;


while (number >= value) {
sb.append(symbol);
number -= value;
}
}


return sb.toString();
}


public static int parse(String roman) {
if (roman.isEmpty()) {
throw new NumberFormatException("The empty string does not comprise a valid Roman number");
}


int number = 0;
int offset = 0;
for (Digit digit : DIGITS) {
int value = digit.value;
int maxArity = digit.maxArity;
String symbol = digit.symbol;


for (int i = 0; i < maxArity && roman.startsWith(symbol, offset); i++) {
number += value;
offset += symbol.length();
}
}
if (offset != roman.length()) {
throw new NumberFormatException(String.format(
"The string '%s' does not comprise a valid Roman number",
roman
));
}
return number;
}


/** TESTS */
public static void main(String[] args) {


/* Demonstrating round-trip for all possible inputs. */


for (int number = 1; number <= 3999; number++) {
String roman = of(number);
int parsed = parse(roman);
if (parsed != number) {
System.err.format(
"ERROR: number: %d, roman: %s, parsed: %d\n",
number,
roman,
parsed
);
}
}


/* Some illegal inputs. */


int[] illegalNumbers = { -1, 0, 4000, 4001 };
for (int illegalNumber : illegalNumbers) {
try {
of(illegalNumber);
System.err.format(
"ERROR: Expected failure on number %d\n",
illegalNumber
);
} catch (IllegalArgumentException e) {
// Failed as expected.
}
}


String[] illegalRomans = { "MMMM", "CDCD", "IM", "T", "", "VV", "DM" };
for (String illegalRoman : illegalRomans) {
try {
parse(illegalRoman);
System.err.format(
"ERROR: Expected failure on roman %s\n",
illegalRoman
);
} catch (NumberFormatException e) {
// Failed as expected.
}
}
}
}

我认为如果你仔细研究罗马数字理论,你就不需要对4、9、40等数字进行映射,因为这个理论告诉我们,如果罗马数字是 IV = 5-1 = 4,因此,当前缀小于后续数字时,你必须从后续数字中减去前一个数字,才能得到实际值,这就是我在解决这个问题的代码中所包含的内容,看一下,如果有必要,指出任何错误,我按照这张表设计了我的逻辑 -http://literacy.kent.edu/Minigrants/Cinci/romanchart.htm

import java.util.Set;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.io.FileReader;
import java.io.IOException;
import java.io.BufferedReader;


public class RomanStringToIntegerConversion {
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)));
String[] romanString = br.readLine().split("");


HashMap<String, Integer> romanToIntegerMap = new HashMap<String, Integer>();
romanToIntegerMap.put("I", 1);
romanToIntegerMap.put("V", 5);
romanToIntegerMap.put("X", 10);
romanToIntegerMap.put("L", 50);
romanToIntegerMap.put("C", 100);
romanToIntegerMap.put("D", 500);
romanToIntegerMap.put("M", 1000);


int numLength = romanString.length;
Set<Integer> lessIndices = new HashSet<Integer>();


for(int i = 0; i < numLength; ++i){
if(i+1 < numLength){
if(romanToIntegerMap.get(romanString[i]) < romanToIntegerMap.get(romanString[i+1]))
lessIndices.add(i);
}
}


int num = 0;
for(int i = 0; i < numLength;){
if(!lessIndices.contains(i)){
num = num + romanToIntegerMap.get(romanString[i]);
++i;
}
else{
num = num + romanToIntegerMap.get(romanString[i+1]) - romanToIntegerMap.get(romanString[i]);
i+=2;
}
}
System.out.println("The integer representation of the roman numeral is : " + num);
}
}

在做了一些研究并分析了上面的答案之后,我得出了以下结论:

package roman;


public class RomanNumbers {




public static final int[] decimal = {1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000};
public static final String[] letters = {"I", "IV", "V", "IX", "X", "XL", "L", "XC", "C", "CD", "D", "CM", "M"};


public static String stringToRoman(int num) {
String roman = "";


if (num < 1 || num > 3999) {
System.out.println("Invalid roman number value!");
}


while (num > 0) {
int maxFound = 0;
for (int i=0; i < decimal.length; i++) {
if (num >= decimal[i]) {
maxFound = i;
}
}
roman += letters[maxFound];
num -= decimal[maxFound];
}


return roman;
}
}

单元测试也通过了:

package roman;


import static org.junit.Assert.*;


import org.junit.Test;


public class RomanNumbersTest {


@Test
public void testReturn1() {
String actual = RomanNumbers.stringToRoman(1);
String expected = "I";
assertEquals(expected, actual);
}


@Test
public void testReturn5() {
String actual = RomanNumbers.stringToRoman(5);
String expected = "V";
assertEquals(expected, actual);
}


@Test
public void testReturn2() {
String actual = RomanNumbers.stringToRoman(2);
String expected = "II";
assertEquals(expected, actual);
}


@Test
public void testReturn4() {
String actual = RomanNumbers.stringToRoman(4);
String expected = "IV";
assertEquals(expected, actual);
}


@Test
public void testReturn399() {
String actual = RomanNumbers.stringToRoman(399);
String expected = "CCCXCIX";
assertEquals(expected, actual);
}


@Test
public void testReturn3992() {
String actual = RomanNumbers.stringToRoman(3992);
String expected = "MMMCMXCII";
assertEquals(expected, actual);
}
}

我注意到从整数到罗马数字很容易翻译,因为每个数字总是有1,5和10(例如,VX表示1-10,XLC表示10-100等等) ,这就是为什么我做了一个罗马数字的数组来得到正确的字母。

在我的示例中,我每次遍历整个数字1,每次使用模运算符得到最后一个数字。然后,在 switch 语句中从当前数字形成 Roman Numerals,并将其添加到 asRomanNumerals 字符串的开头。在数字被翻译之后,它从数字中被移除,并且用于在数组中查找字母的索引随着2(IVX-> XLC)的增加而增加。

public static void main(String[] args) {


// number is the one to be translated into Roman Numerals
int number = 2345;
number = Math.min(3999, Math.max(1, number)); // wraps number between 1-3999
String asRomanNumerals = "";


// Array including numerals in ascending order
String[] RN = {"I", "V", "X", "L", "C", "D", "M" };
int i = 0; // Index used to keep track which digit we are translating
while (number > 0) {
switch(number % 10) {
case 1: asRomanNumerals = RN[i] + asRomanNumerals; break;
case 2: asRomanNumerals = RN[i] + RN[i] + asRomanNumerals; break;
case 3: asRomanNumerals = RN[i] + RN[i] + RN[i] + asRomanNumerals; break;
case 4: asRomanNumerals = RN[i] + RN[i + 1] + asRomanNumerals; break;
case 5: asRomanNumerals = RN[i + 1] + asRomanNumerals; break;
case 6: asRomanNumerals = RN[i + 1] + RN[i] + asRomanNumerals; break;
case 7: asRomanNumerals = RN[i + 1] + RN[i] + RN[i] + asRomanNumerals; break;
case 8: asRomanNumerals = RN[i + 1] + RN[i] + RN[i] + RN[i] +asRomanNumerals; break;
case 9: asRomanNumerals = RN[i] + RN[i + 2] + asRomanNumerals; break;
}
number = (int) number / 10;
i += 2;
}
System.out.println(asRomanNumerals);
}

我写了一个非常简单的解决方案。我们所要做的就是除法,找出一个特定字母(或字母组合)出现的次数,然后将其附加到 StringBuilder 对象 sb。我们还应该跟踪其余的数字(num)。

public static String intToRoman(int num) {
StringBuilder sb = new StringBuilder();
int times = 0;
String[] romans = new String[] { "I", "IV", "V", "IX", "X", "XL", "L",
"XC", "C", "CD", "D", "CM", "M" };
int[] ints = new int[] { 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500,
900, 1000 };
for (int i = ints.length - 1; i >= 0; i--) {
times = num / ints[i];
num %= ints[i];
while (times > 0) {
sb.append(romans[i]);
times--;
}
}
return sb.toString();
}
enum Numeral {
I(1), IV(4), V(5), IX(9), X(10), XL(40), L(50), XC(90), C(100), CD(400), D(500), CM(900), M(1000);
int weight;


Numeral(int weight) {
this.weight = weight;
}
};


public static String roman(long n) {


if( n <= 0) {
throw new IllegalArgumentException();
}


StringBuilder buf = new StringBuilder();


final Numeral[] values = Numeral.values();
for (int i = values.length - 1; i >= 0; i--) {
while (n >= values[i].weight) {
buf.append(values[i]);
n -= values[i].weight;
}
}
return buf.toString();
}


public static void test(long n) {
System.out.println(n + " = " + roman(n));
}


public static void main(String[] args) {
test(1999);
test(25);
test(944);
test(0);
}

这是我作业的结果。它不能确保输入在正确的范围内,我可能应该使用 StringBuilder(当我查找它的时候!)而且不是一个单一的方法。但是如果有人读到这里,我希望得到正面和负面的反馈!

import java.util.Scanner;
/**
*Main() allows user input and tests 1-3999
*toRoman() breaks the number down into digits and passes them to romanLogic()
*romanLogic() converts each digit into a the numerals that represent it.
*/
public class RomanNumerals
{
public static void main(String args[]){
Scanner in = new Scanner(System.in);
System.out.print("give us an integer < 4000: ");
System.out.println("the roman numeral version is: " + toRoman(in.nextInt()));
for (int i = 1; i<=3999; i++){
System.out.println(i +" === "+ toRoman(i));
}
}
public static String toRoman(int i){
String output = "";
int digits = i%10;
int tens = (i%100)/10;
int hundreds = (i%1000)/100;
int thousands = (i%10000)/1000;
return (romanLogic(thousands, "M","","")+
romanLogic(hundreds,"C","D","M")+
romanLogic(tens,"X","L","C")+
romanLogic(digits,"I","V","X"));
}
public static String romanLogic(int i, String ones, String fives, String tens){
String result = "";
if (i == 0){
return result;
} else {
if ((i>=4)&&(i<=8)){
result += fives;
}
if (i==9){
result += tens;
}
if(i%5 < 4){
while(i%5 > 0){
result += ones;
i--;
}
}
if(i%5 == 4){
result = ones + result;
}
}
return result;
}
}
import java.util.Scanner;
import java.io.*;

那么

try {


Scanner input = new Scanner(new File("lettered.in"));


int dataCollect = input.nextInt();


int sum = 0;


String lineInput = "";


for (int i = 0; i <= dataCollect; i++) {


while (input.hasNext()) {


lineInput = input.next();
char lineArray[] = lineInput.toCharArray();


for (int j = 0; j < lineArray.length; j++) {


switch(lineArray[j]) {
case 'A': {
sum += 1;
continue;
}
case 'B': {
sum += 10;
continue;
}
case 'C': {
sum += 100;
}
case 'D': {
sum += 1000;
continue;
}
case 'E': {
sum += 10000;
continue;
}
case 'F': {
sum += 100000;
continue;
}
case: 'G': {
sum += 1000000;
continue;
}
case 'X': {
System.out.println(sum);
sum = 0;
continue;
}
default: {}
}
}
}
}
} catch (FileNotFoundException fileNotFound) {
System.out.println("File has not been found.");
}

这可能会有所帮助:

using System;


using System.Text;


public class Test
{


public static string ToRoman(int number)
{
StringBuilder br=new StringBuilder("");
while(number!=0)
{
if(number>=1000)
{
br.Append("M");
number-=1000;
}
if(number>=900)
{
br.Append("CM");
number-=900;
}
if(number>=500)
{
br.Append("D");
number-=500;
}
if(number>=400)
{
br.Append("CD");
number-=400;
}
if(number>=100)
{
br.Append("C");
number-=100;
}
if(number>=90)
{
br.Append("XC");
number-=90;
}
if(number>=50)
{
br.Append("L");
number-=50;
}
if(number>=40)
{
br.Append("XL");
number-=40;
}
if(number>=10)
{
br.Append("X");
number-=10;
}
if(number>=9)
{
br.Append("IX");
number-=9;
}
if(number>=5)
{
br.Append("V");
number-=5;
}
if(number>=4)
{
br.Append("IV");
number-=4;
}
if(number>=1)
{
br.Append("I");
number-=1;
}
}
return br.ToString();
}
public static void Main()
{
Console.WriteLine(ToRoman(int.Parse(Console.ReadLine())));
}
}

我认为我的解决方案比较简洁:

private static String convertToRoman(int mInt) {
String[] rnChars = { "M",  "CM", "D", "C",  "XC", "L",  "X", "IX", "V", "I" };
int[] rnVals = {  1000, 900, 500, 100, 90, 50, 10, 9, 5, 1 };
String retVal = "";


for (int i = 0; i < rnVals.length; i++) {
int numberInPlace = mInt / rnVals[i];
if (numberInPlace == 0) continue;
retVal += numberInPlace == 4 && i > 0? rnChars[i] + rnChars[i - 1]:
new String(new char[numberInPlace]).replace("\0",rnChars[i]);
mInt = mInt % rnVals[i];
}
return retVal;
}

最简单的解决办法:

public class RomanNumerals {


private static int [] arabic = {50, 40, 10, 9, 5, 4, 1};


private static String [] roman = {"L", "XL", "X", "IX", "V", "IV", "I"};


public static String convert(int arabicNumber) {


StringBuilder romanNumerals = new StringBuilder();
int remainder = arabicNumber;


for (int i=0;i<arabic.length;i++) {


while (remainder >= arabic[i]) {
romanNumerals.append(roman[i]);
remainder -= arabic[i];
}
}


return romanNumerals.toString();
}
}

实际上还有另一种方法来看待这个问题,不是数字问题,而是一元问题,从罗马数字的基本字符“ I”开始。所以我们只用 I 表示数字,然后用罗马字符的升值替换字符。

public String getRomanNumber(int number) {
return join("", nCopies(number, "I"))
.replace("IIIII", "V")
.replace("IIII", "IV")
.replace("VV", "X")
.replace("VIV", "IX")
.replace("XXXXX", "L")
.replace("XXXX", "XL")
.replace("LL", "C")
.replace("LXL", "XC")
.replace("CCCCC", "D")
.replace("CCCC", "CD")
.replace("DD", "M")
.replace("DCD", "CM");
}

我特别喜欢这种解决这个问题的方法,而不是使用大量的 if 和 while 循环或表查找。当你认为问题不是一个数字问题时,它实际上也是一个退出直观的解决方案。

我喜欢 André Kramer Orten 的回答,非常优雅,我特别喜欢它避免循环的方式,我想到了另一种处理方式,也避免了循环。

它对输入使用整数除法和模来从一组硬编码的字符串数组中为每个单元类型选择正确的索引。

这里的好处是,您可以指定精确的转换,这取决于您是否需要加法或减法数字形式,即 III 与 IV。在这里,我用“减法形式”来表示5x-1(4、9、14、19、40、90等)中的所有数字

通过简单地使用进一步的加法或减法形式(例如“ IV”、“ V”或“ MMMM”、“ MMMMM”)扩展数千个数组来允许更大的数量也是微不足道的

对于额外的分数,我实际上确保数字参数是在给定的范围内的问题。

public class RomanNumeralGenerator {
static final int MIN_VALUE = 1;
static final int MAX_VALUE = 3999;
static final String[] RN_M = {"", "M", "MM", "MMM"};
static final String[] RN_C = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
static final String[] RN_X = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
static final String[] RN_I = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};


public String generate(int number) {
if (number < MIN_VALUE || number > MAX_VALUE) {
throw new IllegalArgumentException(
String.format(
"The number must be in the range [%d, %d]",
MIN_VALUE,
MAX_VALUE
)
);
}


return new StringBuilder()
.append(RN_M[number / 1000])
.append(RN_C[number % 1000 / 100])
.append(RN_X[number % 100 / 10])
.append(RN_I[number % 10])
.toString();
}
}
private String convertToRoman(int num) {
String result = "";
while(num > 0){
if(num >= 1000){
result += "M";
num -= 1000;
}else if(num >= 900){
result += "CM";
num -= 900;
}
else if(num >= 500){
result += "D";
num -= 500;
}else if(num >= 400){
result += "CD";
num -= 400;
}else if(num >= 100){
result += "C";
num -= 100;
}else if(num >= 90){
result += "XC";
num -= 90;
}else if(num >= 50){
result += "L";
num -= 50;
}else if(num >= 40){
result += "XL";
num -= 40;
}
else if(num >= 10){
result += "X";
num -= 10;
}else if(num >= 9){
result += "IX";
num -= 9;
}
else if(num >= 5){
result += "V";
num -= 5;
}else if(num >= 4){
result += "IV";
num -= 4;
}else if(num >= 1){
result += "I";
num -= 1;
}


else{
break;
}
}


return result;
}

我三年前就这么做了,也许对你有帮助:

public class ToRoman
{


public static String toRoman(int number)
{
StringBuilder br = new StringBuilder("");
while(number!=0)
{
while(number>=1000)
{
br.append("M");
number-=1000;
}
while(number>=900)
{
br.append("CM");
number-=900;
}
while(number>=500)
{
br.append("D");
number-=500;
}
while(number>=400)
{
br.append("CD");
number-=400;
}
while(number>=100)
{
br.append("C");
number-=100;
}
while(number>=90)
{
br.append("XC");
number-=90;
}
while(number>=50)
{
br.append("L");
number-=50;
}
while(number>=40)
{
br.append("XL");
number-=40;
}
while(number>=10)
{
br.append("X");
number-=10;
}
while(number>=9)
{
br.append("IX");
number-=9;
}
while(number>=5)
{
br.append("V");
number-=5;
}
while(number>=4)
{
br.append("IV");
number-=4;
}
while(number>=1)
{
br.append("I");
number-=1;
}
}
return br.toString();
}


public static void main(String [] args)
{
System.out.println(toRoman(2000));
}
}
private static String toRoman(int n) {
String[] romanNumerals = { "M",  "CM", "D", "CD", "C", "XC", "L",  "X", "IX", "V", "I" };
int[] romanNumeralNums = {  1000, 900, 500,  400 , 100,  90,  50,   10,    9,   5,   1 };
String finalRomanNum = "";


for (int i = 0; i < romanNumeralNums.length; i ++) {
int currentNum = n /romanNumeralNums[i];
if (currentNum==0) {
continue;
}


for (int j = 0; j < currentNum; j++) {
finalRomanNum +=romanNumerals[i];
}


n = n%romanNumeralNums[i];
}
return finalRomanNum;
}

为了跟上技术的发展,这里有一个使用流和自定义 Collector 的 Java8版本,它消除了循环或 if 语句的需要:

import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.IntStream;


public class RomanNumeral {


public static void main(String arg[]) {
IntStream.range(1, 4000).forEach(value -> System.out.println( Arrays.stream(Mark.values()).collect(new MarkCollector<Mark>(value)).toString()));
}


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


private final int value;


private Mark(int value) { this.value = value; }


public int value() { return value; }
}


static class MarkCollector<T extends Mark> implements Collector<T, StringBuilder, StringBuilder> {


private final int[] valueholder = new int[1];


MarkCollector(int value) { valueholder[0] = value; }


@Override
public Supplier<StringBuilder> supplier() { return () -> StringBuilder::new; }


@Override
public BiConsumer<StringBuilder, T> accumulator() {
return (builder, mark) -> {
builder.append(String.join("", Collections.nCopies(valueholder[0] / mark.value(), mark.name())));
valueholder[0] = valueholder[0] % mark.value();
};
}


@Override
public BinaryOperator<StringBuilder> combiner() { return null; }


@Override
public Function<StringBuilder, StringBuilder> finisher() { return Function.identity(); }


@Override
public Set<Characteristics> characteristics() { return Collections.singleton(Characteristics.IDENTITY_FINISH); }
}
}

我自己喜欢使用 责任链模式。我认为这对于这个场景很有意义。

public abstract class NumberChainOfResponsibility {
protected NumberChainOfResponsibility next;
protected int decimalValue;
protected String romanNumeralValue;


public NumberChainOfResponsibility() {
}


public String convert(int decimal) {
int remainder = decimal;
StringBuilder numerals = new StringBuilder();
while (remainder != 0) {
if (remainder >= this.decimalValue) {
numerals.append(this.romanNumeralValue);
remainder -= this.decimalValue;
} else {
numerals.append(next.convert(remainder));
remainder = 0;
}
}
return numerals.toString();
}
}

然后我创建一个类,对每个罗马数字(1/5/10/50/100/500/1000以及4/9/40/90/400/900)扩展这个类。

1000

public class Cor1000 extends NumberChainOfResponsibility {
public Cor1000() {
super();
this.decimalValue = 1000;
this.romanNumeralValue = "M";
this.next = new Cor900();
}
}

1

public class Cor1 extends NumberChainOfResponsibility {
public Cor1() {
super();
this.decimalValue = 1;
this.romanNumeralValue = "I";
this.next = null;
}
}

作为转换器的“接口”的类,公开转换特定数字的方法。

public class Converter {
private static int MAX_VALUE = 5000;
private static int MIN_VALUE = 0;
private static String ERROR_TOO_BIG = "Value is too big!";
private static String ERROR_TOO_SMALL = "Value is too small!";


public String convertThisIntToRomanNumerals(int decimal) {
Cor1000 startingCor = new Cor1000();
if (decimal >= MAX_VALUE)
return ERROR_TOO_BIG;
if (decimal <= MIN_VALUE)
return ERROR_TOO_SMALL;


String numeralsWithoutConversion = startingCor.convert(decimal);
return numeralsWithoutConversion;
}
}

以及客户机代码(在我的例子中是 JUnit 测试)。

@Test
public void assertConversionWorks() {
Assert.assertEquals("MMMMCMXCIX", converter.convertThisIntToRomanNumerals(4999));
Assert.assertEquals("CMXCIX", converter.convertThisIntToRomanNumerals(999));
Assert.assertEquals("CMLXXXIX", converter.convertThisIntToRomanNumerals(989));
Assert.assertEquals("DCXXVI", converter.convertThisIntToRomanNumerals(626));
Assert.assertEquals("DCXXIV", converter.convertThisIntToRomanNumerals(624));
Assert.assertEquals("CDXCVIII", converter.convertThisIntToRomanNumerals(498));
Assert.assertEquals("CXXIII", converter.convertThisIntToRomanNumerals(123));
Assert.assertEquals("XCIX", converter.convertThisIntToRomanNumerals(99));
Assert.assertEquals("LI", converter.convertThisIntToRomanNumerals(51));
Assert.assertEquals("XLIX", converter.convertThisIntToRomanNumerals(49));
}

在我的 Github 账户上可以看到整个例子。

首先将数字分解成小数因子,比如995 = 900 + 90 + 5,然后递归地转换每个因子

public class IntegerToRoman {
private Map<Integer, String> romanChars = new HashMap<>();


public IntegerToRoman() {
romanChars.put(1, "I");
romanChars.put(5, "V");
romanChars.put(10, "X");
romanChars.put(50, "L");
romanChars.put(100, "C");
romanChars.put(500, "D");
romanChars.put(1000, "M");
romanChars.put(5000, "V|");
}


public String intToRoman(int num) {
if (num == 0) {
return "";
}
int decimalFact = 0;
StringBuilder result = new StringBuilder();
for (int i = (int)Math.log10(num); i >= 0; i--) {
int divisor = (int) Math.pow(10, i);
decimalFact = num - num % divisor;
result.append(convertDecimalFact(decimalFact));
num = num % divisor;
}
return result.toString();
}


private String convertDecimalFact(int decimalFact){
if(decimalFact == 0){return "";}
int[] keyArray = romanChars.keySet().stream().mapToInt(key -> key)
.sorted().toArray();


for(int i =0 ; i+1<keyArray.length ; i++){
if( keyArray[i] <= decimalFact && decimalFact<= keyArray[i+1]  ){
int bigger1stDgt = getLeftMostNum(keyArray[i+1]);
int decimalFact1stDgt = getLeftMostNum(decimalFact);
return decimalFact1stDgt >= bigger1stDgt-1 ?
intToRoman(keyArray[i+1]-decimalFact)+romanChars.get(keyArray[i+1]):
romanChars.get(keyArray[i])+intToRoman(decimalFact - keyArray[i]);
}
}
return "";
}


private int getLeftMostNum(int number) {
int oneDgt = Integer.valueOf(Integer.valueOf(number).toString()
.substring(0, 0 +1));
if(number<10){
return oneDgt;
}
int twoDgts = Integer.valueOf(Integer.valueOf(number).toString()
.substring(0, 0 +2));
return twoDgts==10 ? twoDgts : oneDgt;
}


public static void main(String[] args) {


IntegerToRoman solution = new IntegerToRoman();
System.out.format(" Decimal 3 -> Roman %s \n ", solution.intToRoman(3));
System.out.format("Decimal 4 -> Roman %s \n ", solution.intToRoman(4));
System.out.format("Decimal 8 -> Roman %s \n ", solution.intToRoman(8));
System.out.format("Decimal 58 -> Roman %s \n ", solution.intToRoman(58));
System.out.format("Decimal 344 -> Roman %s \n ", solution.intToRoman(344));
System.out.format("Decimal 995 -> Roman %s \n ", solution.intToRoman(995));
System.out.format("Decimal 1994 -> Roman %s \n ", solution.intToRoman(1994));
}

}

输出是这样的:

十进制3-> 罗马三

十进制4-> 罗马四

十进制8-> 罗马八

十进制58-> 罗马 LVIII

十进制344-> 罗马 CCCXLIV

十进制995-> 罗马 CMXCV

1994年十进制-> 罗马 MCMXCIV

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

我想接下来的内容会很简短明了:

public class IntegerToRoman {
public static String intToRoman(int number) {
String[] thousands = {"", "M", "MM", "MMM"};
String[] hundreds = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
String[] tens = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
String[] units = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};


return thousands[number / 1000]
+ hundreds[(number % 1000) / 100]
+ tens[(number % 100) / 10]
+ units[number % 10];
}


public static void main(String[] args) {
int[] numbers = {1, 2, 3, 5, 10, 14, 17, 20, 25, 38, 49, 63, 72, 81, 97, 98, 99, 100, 101, 248, 253, 799, 1325, 1900, 2000, 2456, 1715};


final Instant startTimeIter = Instant.now();
for (int number : numbers) {
System.out.printf("%4d -> %8s\n", number, intToRoman(number));
}
final Instant endTimeIter = Instant.now();
System.out.printf("Elapsed time: %d ms\n\n", Duration.between(startTimeIter, endTimeIter).toMillis());
}
}

产出:

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

逻辑很简单:

  • 我们只需要从左到右遍历整数
  • 并为每个数字取适当的数组值(千,百...)
  • 这种方法可以转换到 3000

我们可以避免这个循环,如果有了这个解决方案:

public class RomanNumber {


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


private static Function<TreeMap<Integer, String>, Function<Integer, String>> numeralConverter = map -> number -> Optional
.ofNullable(map.floorKey(number))
.filter(number::equals)
.map(map::get)
.or(() -> Optional
.ofNullable(map.floorKey(number))
.map(num -> map.get(num) + RomanNumber.numeralConverter.apply(map).apply(number - num))
).orElse("NaN");


public static Function<Integer, String> toRoman = numeralConverter.apply(romanNumerals.get());
}

我认为与其采用两个独立的数组,不如使用一个单独的数组。 此外,我建议 地图上的数组。阵列保证 O (1)的复杂性,以获得任何情况下的任何元素,如果我们知道的位置。
由于频繁的追加操作,我使用的是 StringBuilder而不是 绳子

class Solution {
    

public String intToRoman(int num) {
StringBuilder str = new StringBuilder();
RomanDataStore arr[]=new RomanDataStore[13];
arr[0]=new RomanDataStore(1000,"M");
arr[1]=new RomanDataStore(900, "CM");
arr[2]=new RomanDataStore(500, "D");
arr[3]=new RomanDataStore(400, "CD");
arr[4]=new RomanDataStore(100, "C");
arr[5]=new RomanDataStore(90, "XC");
arr[6]=new RomanDataStore(50, "L");
arr[7]=new RomanDataStore(40, "XL");
arr[8]=new RomanDataStore(10, "X");
arr[9]=new RomanDataStore(9, "IX");
arr[10]=new RomanDataStore(5, "V");
arr[11]=new RomanDataStore(4, "IV");
arr[12]=new RomanDataStore(1, "I");
int itr=0;
RomanDataStore temp=null;
while(num!=0){
temp=arr[itr];
if(num>=temp.val){
for(int i=0;i<num/temp.val;i++){
str.append(temp.s);
}
num=num%temp.val;
}
itr++;
        

}
return str.toString();
        

}
    

private class RomanDataStore{
private int val;
private String s;
RomanDataStore(int val, String s){
this.val=val;
this.s=s;
}
}
}