首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >让我们重温罗马数字

让我们重温罗马数字
EN

Code Review用户
提问于 2016-05-19 16:54:30
回答 1查看 452关注 0票数 5

问题陈述:

编写一个函数,将法线数字转换为罗马数字。

代码语言:javascript
运行
复制
 1  => I
10  => X
 7  => VII

代码:

代码语言:javascript
运行
复制
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;
  }
}

测试套件:

代码语言:javascript
运行
复制
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

EN

回答 1

Code Review用户

回答已采纳

发布于 2016-05-19 21:32:45

您的代码非常清晰,而且编写得很好。而且,使用TreeMap来利用有序的键是非常有洞察力的。

总的来说,我实际上只对代码有很好的评论:

  • 在一个负数或大于3000个数字的情况下抛出一个IllegalArgumentException是一个很好的方式来记录这些值是不允许的。
  • 递归方法toRomen正确地处理所有情况。您在方法的名称中做了一个小错误:它应该是toRoman而不是toRomen
  • NavigableMap接口进行编码并将TreeMap具体实例化隐藏在方法中是一件好事。
  • 使用缓存确实是个好主意:它有助于确保相同的罗马数字不被每次转换,而且,由于我们最多只对3000个数字感兴趣,这张地图不会变得庞大,消耗大量的内存。

我还有几个建议:

  • 您目前在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将被调用,将其作为参数,缓存将使用该函数返回的值进行更新,该值将被返回。
票数 5
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/128777

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档