Enhance docs, add more tests in RomanToInteger (#5926)

This commit is contained in:
Hardik Pawar
2024-10-23 11:55:20 +05:30
committed by GitHub
parent aaaf96b05f
commit 7bbdae5fe0
2 changed files with 73 additions and 31 deletions

View File

@ -3,9 +3,27 @@ package com.thealgorithms.conversions;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; 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 { public final class RomanToInteger {
private RomanToInteger() {
}
private static final Map<Character, Integer> ROMAN_TO_INT = new HashMap<>() { 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) { private static int romanSymbolToInt(final char symbol) {
return ROMAN_TO_INT.computeIfAbsent(symbol, c -> { throw new IllegalArgumentException("Unknown Roman symbol: " + c); }); 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 * @param roman the Roman numeral string
* @return integer * @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) { public static int romanToInt(String roman) {
a = a.toUpperCase(); if (roman == null) {
char prev = ' '; throw new NullPointerException("Input cannot be null");
}
roman = roman.toUpperCase();
int sum = 0; int sum = 0;
int maxPrevValue = 0;
int newPrev = 0; for (int i = roman.length() - 1; i >= 0; i--) {
for (int i = a.length() - 1; i >= 0; i--) { int currentValue = romanSymbolToInt(roman.charAt(i));
char c = a.charAt(i); if (currentValue >= maxPrevValue) {
sum += currentValue;
if (prev != ' ') { maxPrevValue = currentValue;
// 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;
} else { } else {
// subtract upcoming number until upcoming number not greater than prev max sum -= currentValue;
sum -= currentNum;
} }
prev = c;
} }
return sum; return sum;

View File

@ -8,16 +8,31 @@ import org.junit.jupiter.api.Test;
public class RomanToIntegerTest { public class RomanToIntegerTest {
@Test @Test
public void testRomanToInteger() { public void testValidRomanToInteger() {
assertEquals(1994, RomanToInteger.romanToInt("MCMXCIV")); assertEquals(1994, RomanToInteger.romanToInt("MCMXCIV"));
assertEquals(58, RomanToInteger.romanToInt("LVIII")); assertEquals(58, RomanToInteger.romanToInt("LVIII"));
assertEquals(1804, RomanToInteger.romanToInt("MDCCCIV")); assertEquals(1804, RomanToInteger.romanToInt("MDCCCIV"));
assertEquals(9, RomanToInteger.romanToInt("IX"));
assertEquals(4, RomanToInteger.romanToInt("IV"));
assertEquals(3000, RomanToInteger.romanToInt("MMM"));
} }
@Test @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("Z"));
assertThrows(IllegalArgumentException.class, () -> RomanToInteger.romanToInt("MZI")); assertThrows(IllegalArgumentException.class, () -> RomanToInteger.romanToInt("MZI"));
assertThrows(IllegalArgumentException.class, () -> RomanToInteger.romanToInt("MMMO")); 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
}
} }