mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-05 08:17:33 +08:00
Enhance docs, add more tests in RomanToInteger
(#5926)
This commit is contained in:
@ -3,9 +3,27 @@ package com.thealgorithms.conversions;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A utility class to convert Roman numerals into integers.
|
||||
*
|
||||
* <p>Roman numerals are based on seven symbols given below:
|
||||
* <ul>
|
||||
* <li>I = 1</li>
|
||||
* <li>V = 5</li>
|
||||
* <li>X = 10</li>
|
||||
* <li>L = 50</li>
|
||||
* <li>C = 100</li>
|
||||
* <li>D = 500</li>
|
||||
* <li>M = 1000</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>If a smaller numeral appears before a larger numeral, it is subtracted.
|
||||
* Otherwise, it is added. For example:
|
||||
* <pre>
|
||||
* MCMXCIV = 1000 + (1000 - 100) + (100 - 10) + (5 - 1) = 1994
|
||||
* </pre>
|
||||
*/
|
||||
public final class RomanToInteger {
|
||||
private RomanToInteger() {
|
||||
}
|
||||
|
||||
private static final Map<Character, Integer> ROMAN_TO_INT = new HashMap<>() {
|
||||
{
|
||||
@ -19,44 +37,53 @@ public final class RomanToInteger {
|
||||
}
|
||||
};
|
||||
|
||||
private RomanToInteger() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a single Roman numeral character to its integer value.
|
||||
*
|
||||
* @param symbol the Roman numeral character
|
||||
* @return the corresponding integer value
|
||||
* @throws IllegalArgumentException if the symbol is not a valid Roman numeral
|
||||
*/
|
||||
private static int romanSymbolToInt(final char symbol) {
|
||||
return ROMAN_TO_INT.computeIfAbsent(symbol, c -> { throw new IllegalArgumentException("Unknown Roman symbol: " + c); });
|
||||
}
|
||||
|
||||
// Roman Number = Roman Numerals
|
||||
|
||||
/**
|
||||
* This function convert Roman number into Integer
|
||||
* Converts a Roman numeral string to its integer equivalent.
|
||||
* Steps:
|
||||
* <ol>
|
||||
* <li>Iterate over the string from right to left.</li>
|
||||
* <li>For each character, convert it to an integer value.</li>
|
||||
* <li>If the current value is greater than or equal to the max previous value, add it.</li>
|
||||
* <li>Otherwise, subtract it from the sum.</li>
|
||||
* <li>Update the max previous value.</li>
|
||||
* <li>Return the sum.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param a Roman number string
|
||||
* @return integer
|
||||
* @param roman the Roman numeral string
|
||||
* @return the integer value of the Roman numeral
|
||||
* @throws IllegalArgumentException if the input contains invalid Roman characters
|
||||
* @throws NullPointerException if the input is {@code null}
|
||||
*/
|
||||
public static int romanToInt(String a) {
|
||||
a = a.toUpperCase();
|
||||
char prev = ' ';
|
||||
public static int romanToInt(String roman) {
|
||||
if (roman == null) {
|
||||
throw new NullPointerException("Input cannot be null");
|
||||
}
|
||||
|
||||
roman = roman.toUpperCase();
|
||||
int sum = 0;
|
||||
|
||||
int newPrev = 0;
|
||||
for (int i = a.length() - 1; i >= 0; i--) {
|
||||
char c = a.charAt(i);
|
||||
|
||||
if (prev != ' ') {
|
||||
// checking current Number greater than previous or not
|
||||
newPrev = romanSymbolToInt(prev) > newPrev ? romanSymbolToInt(prev) : newPrev;
|
||||
}
|
||||
|
||||
int currentNum = romanSymbolToInt(c);
|
||||
|
||||
// if current number greater than prev max previous then add
|
||||
if (currentNum >= newPrev) {
|
||||
sum += currentNum;
|
||||
int maxPrevValue = 0;
|
||||
for (int i = roman.length() - 1; i >= 0; i--) {
|
||||
int currentValue = romanSymbolToInt(roman.charAt(i));
|
||||
if (currentValue >= maxPrevValue) {
|
||||
sum += currentValue;
|
||||
maxPrevValue = currentValue;
|
||||
} else {
|
||||
// subtract upcoming number until upcoming number not greater than prev max
|
||||
sum -= currentNum;
|
||||
sum -= currentValue;
|
||||
}
|
||||
|
||||
prev = c;
|
||||
}
|
||||
|
||||
return sum;
|
||||
|
@ -8,16 +8,31 @@ import org.junit.jupiter.api.Test;
|
||||
public class RomanToIntegerTest {
|
||||
|
||||
@Test
|
||||
public void testRomanToInteger() {
|
||||
public void testValidRomanToInteger() {
|
||||
assertEquals(1994, RomanToInteger.romanToInt("MCMXCIV"));
|
||||
assertEquals(58, RomanToInteger.romanToInt("LVIII"));
|
||||
assertEquals(1804, RomanToInteger.romanToInt("MDCCCIV"));
|
||||
assertEquals(9, RomanToInteger.romanToInt("IX"));
|
||||
assertEquals(4, RomanToInteger.romanToInt("IV"));
|
||||
assertEquals(3000, RomanToInteger.romanToInt("MMM"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRomanToIntegerThrows() {
|
||||
public void testLowercaseInput() {
|
||||
assertEquals(1994, RomanToInteger.romanToInt("mcmxciv"));
|
||||
assertEquals(58, RomanToInteger.romanToInt("lviii"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidRomanNumerals() {
|
||||
assertThrows(IllegalArgumentException.class, () -> RomanToInteger.romanToInt("Z"));
|
||||
assertThrows(IllegalArgumentException.class, () -> RomanToInteger.romanToInt("MZI"));
|
||||
assertThrows(IllegalArgumentException.class, () -> RomanToInteger.romanToInt("MMMO"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyAndNullInput() {
|
||||
assertEquals(0, RomanToInteger.romanToInt("")); // Empty string case
|
||||
assertThrows(NullPointerException.class, () -> RomanToInteger.romanToInt(null)); // Null input case
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user