编写一个函数,将法线数字转换为罗马数字。
1 => I
10 => X
7 => VII
import java.util.HashMap;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
public class RomanNumeral {
private final int number;
private static final Map<Integer, String> CACHE = new HashMap<>();
private static final NavigableMap<Integer, String> NUMBER_TO_ROMAN =
initMap();
public RomanNumeral(int number) {
if (number < 0 || number > 3000) {
throw new IllegalArgumentException("Number out of range.");
}
this.number = number;
}
public String getRomanNumeral() {
if (number == 0) {
return "";
}
String result = CACHE.get(number);
if (result != null) {
return result;
}
result = toRomen(number);
CACHE.put(number, result);
return result;
//return number == 0 ? "" : toRomen(number);
}
private static String toRomen(int num) {
int floorNum = NUMBER_TO_ROMAN.floorKey(num);
// Base case
if (floorNum == num) {
return NUMBER_TO_ROMAN.get(num);
}
return NUMBER_TO_ROMAN.get(floorNum) + toRomen(num - floorNum);
}
private static NavigableMap<Integer, String> initMap() {
NavigableMap<Integer, String> map = new TreeMap<>();
map.put(1, "I");
map.put(4, "IV");
map.put(5, "V");
map.put(9, "IX");
map.put(10, "X");
map.put(40, "XL");
map.put(50, "L");
map.put(90, "XC");
map.put(100, "C");
map.put(400, "CD");
map.put(500, "D");
map.put(900, "CM");
map.put(1000, "M");
return map;
}
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
@RunWith(Parameterized.class)
public class RomanNumeralsTest {
private int input;
private String expectedOutput;
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{0, ""},
{1, "I"},
{2, "II"},
{3, "III"},
{4, "IV"},
{5, "V"},
{6, "VI"},
{9, "IX"},
{27, "XXVII"},
{48, "XLVIII"},
{59, "LIX"},
{93, "XCIII"},
{141, "CXLI"},
{163, "CLXIII"},
{402, "CDII"},
{575, "DLXXV"},
{911, "CMXI"},
{1024, "MXXIV"},
{3000, "MMM"}
});
}
public RomanNumeralsTest(int input, String expectedOutput) {
this.input = input;
this.expectedOutput = expectedOutput;
}
@Test
public void convertArabicNumberalToRomanNumeral() {
RomanNumeral romanNumeral = new RomanNumeral(input);
assertEquals(expectedOutput, romanNumeral.getRomanNumeral());
}
}
TreeMap
来订购钥匙了。CACHING
,因为我不想一次又一次地做同样的计算。http://exercism.io/exercises/java/roman-numerals/readme
发布于 2016-05-19 21:32:45
您的代码非常清晰,而且编写得很好。而且,使用TreeMap
来利用有序的键是非常有洞察力的。
总的来说,我实际上只对代码有很好的评论:
IllegalArgumentException
是一个很好的方式来记录这些值是不允许的。toRomen
正确地处理所有情况。您在方法的名称中做了一个小错误:它应该是toRoman
而不是toRomen
。NavigableMap
接口进行编码并将TreeMap
具体实例化隐藏在方法中是一件好事。我还有几个建议:
getRomanNumeral
内部的一个特殊的早期返回中处理数字0: if ( == 0) {==“;}严格来说这不是必需的。这样做是因为toRomen
没有将0作为输入处理。处理0可以在toRomen
内部完成。考虑以下情况:私有静态字符串toRoman(int ){ if (num == 0) {==“;} int floorNum = NUMBER_TO_ROMAN.floorKey( num);返回NUMBER_TO_ROMAN.get(floorNum) + toRoman(num - floorNum);}现在方法toRoman
有一个明确的基本情况:当给定的数字为0时,我们返回一个空字符串。当两者相等时,这也会处理num - floorNum
的递归调用:我们将在本例中处理并返回空字符串。getRomanNumeral
现在变成:公共字符串getRomanNumeral() { String = CACHE.get(number);if (结果!= null) {返回结果;} result = toRomen(number);CACHE.put(number,result);返回结果;}我们可以使用Java 8中引入的方法使其更短。主要是,我们对这里的computeIfAbsent(key, mappingFunction)
方法感兴趣。此方法将将当前映射的值返回给给定的键,或者在没有映射时调用给定的映射函数。因此,我们可以在这里简单地拥有:公共字符串getRomanNumeral() {返回CACHE.computeIfAbsent(number,RomanNumeral::toRoman);}当缓存已经包含number
的值时,它将直接返回。否则,方法toRoman
将被调用,将其作为参数,缓存将使用该函数返回的值进行更新,该值将被返回。https://codereview.stackexchange.com/questions/128777
复制相似问题