diff --git a/DIRECTORY.md b/DIRECTORY.md index 19e041797ed1..931e76957ee3 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -704,6 +704,7 @@ * [NextFitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/NextFitTest.java) * [PasswordGenTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/PasswordGenTest.java) * [SieveOfEratosthenesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/SieveOfEratosthenesTest.java) + * [StackPostfixNotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/StackPostfixNotationTest.java) * [TestPrintMatrixInSpiralOrder](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java) * [TwoPointersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TwoPointersTest.java) * [UniquePathsTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/UniquePathsTests.java) diff --git a/pom.xml b/pom.xml index accdd2174d80..82b239e48e63 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,11 @@ 5.9.0 test + + org.apache.commons + commons-lang3 + 3.12.0 + diff --git a/src/main/java/com/thealgorithms/maths/AmicableNumber.java b/src/main/java/com/thealgorithms/maths/AmicableNumber.java index ea9cd672baea..7e7b454ac18a 100644 --- a/src/main/java/com/thealgorithms/maths/AmicableNumber.java +++ b/src/main/java/com/thealgorithms/maths/AmicableNumber.java @@ -1,81 +1,69 @@ package com.thealgorithms.maths; +import java.util.LinkedHashSet; +import java.util.Set; +import org.apache.commons.lang3.tuple.Pair; + /** - * Amicable numbers are two different numbers so related that the sum of the - * proper divisors of each is equal to the other number. (A proper divisor of a - * number is a positive factor of that number other than the number itself. For - * example, the proper divisors of 6 are 1, 2, and 3.) A pair of amicable - * numbers constitutes an aliquot sequence of period 2. It is unknown if there - * are infinitely many pairs of amicable numbers. * + * Amicable numbers are two different natural numbers that the sum of the + * proper divisors of each is equal to the other number. + * (A proper divisor of a number is a positive factor of that number other than the number itself. + * For example, the proper divisors of 6 are 1, 2, and 3.) + * A pair of amicable numbers constitutes an aliquot sequence of period 2. + * It is unknown if there are infinitely many pairs of amicable numbers. * *

- * link: https://en.wikipedia.org/wiki/Amicable_numbers * - * + * link: https://en.wikipedia.org/wiki/Amicable_numbers *

- * Simple Example : (220,284) 220 is divisible by {1,2,4,5,10,11,20,22,44,55,110 - * } <- Sum = 284 - * 284 is divisible by -> 1,2,4,71,142 and the Sum of that is. Yes right you - * probably expected it 220 + * Simple Example : (220, 284) + * 220 is divisible by {1,2,4,5,10,11,20,22,44,55,110} <- SUM = 284 + * 284 is divisible by {1,2,4,71,142} <- SUM = 220. */ public class AmicableNumber { - - public static void main(String[] args) { - AmicableNumber.findAllInRange(1, 3000); - /* Res -> Int Range of 1 till 3000there are 3Amicable_numbers These are 1: = ( 220,284) - 2: = ( 1184,1210) 3: = ( 2620,2924) So it worked */ - } - /** - * @param startValue - * @param stopValue - * @return + * Finds all the amicable numbers in a given range. + * + * @param from range start value + * @param to range end value (inclusive) + * @return list with amicable numbers found in given range. */ - static void findAllInRange(int startValue, int stopValue) { - /* the 2 for loops are to avoid to double check tuple. For example (200,100) and (100,200) - * is the same calculation also to avoid is to check the number with it self. a number with - * itself is always a AmicableNumber - * */ - StringBuilder res = new StringBuilder(); - int countofRes = 0; + public static Set> findAllInRange(int from, int to) { + if (from <= 0 || to <= 0 || to < from) { + throw new IllegalArgumentException("Given range of values is invalid!"); + } + + Set> result = new LinkedHashSet<>(); - for (int i = startValue; i < stopValue; i++) { - for (int j = i + 1; j <= stopValue; j++) { + for (int i = from; i < to; i++) { + for (int j = i + 1; j <= to; j++) { if (isAmicableNumber(i, j)) { - countofRes++; - res.append("" + countofRes + ": = ( " + i + "," + j + ")" - + "\t"); + result.add(Pair.of(i, j)); } } } - res.insert(0, "Int Range of " + startValue + " till " + stopValue + " there are " + countofRes + " Amicable_numbers.These are \n "); - System.out.println(res); + return result; } /** - * Check if {@code numberOne and numberTwo } are AmicableNumbers or not - * - * @param numberOne numberTwo - * @return {@code true} if {@code numberOne numberTwo} isAmicableNumbers - * otherwise false + * Checks whether 2 numbers are AmicableNumbers or not. */ - static boolean isAmicableNumber(int numberOne, int numberTwo) { - return ((recursiveCalcOfDividerSum(numberOne, numberOne) == numberTwo && numberOne == recursiveCalcOfDividerSum(numberTwo, numberTwo))); + public static boolean isAmicableNumber(int a, int b) { + if (a <= 0 || b <= 0) { + throw new IllegalArgumentException("Input numbers must be natural!"); + } + return sumOfDividers(a, a) == b && sumOfDividers(b, b) == a; } /** - * calculated in recursive calls the Sum of all the Dividers beside it self - * - * @param number div = the next to test dividely by using the modulo - * operator - * @return sum of all the dividers + * Recursively calculates the sum of all dividers for a given number excluding the divider itself. */ - static int recursiveCalcOfDividerSum(int number, int div) { - if (div == 1) { + private static int sumOfDividers(int number, int divisor) { + if (divisor == 1) { return 0; - } else if (number % --div == 0) { - return recursiveCalcOfDividerSum(number, div) + div; + } else if (number % --divisor == 0) { + return sumOfDividers(number, divisor) + divisor; } else { - return recursiveCalcOfDividerSum(number, div); + return sumOfDividers(number, divisor); } } } diff --git a/src/test/java/com/thealgorithms/maths/AmicableNumberTest.java b/src/test/java/com/thealgorithms/maths/AmicableNumberTest.java index 7c880750c410..14679f22636a 100644 --- a/src/test/java/com/thealgorithms/maths/AmicableNumberTest.java +++ b/src/test/java/com/thealgorithms/maths/AmicableNumberTest.java @@ -2,14 +2,57 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.util.Set; +import org.apache.commons.lang3.tuple.Pair; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class AmicableNumberTest { + private static final String INVALID_RANGE_EXCEPTION_MESSAGE = "Given range of values is invalid!"; + private static final String INVALID_NUMBERS_EXCEPTION_MESSAGE = "Input numbers must be natural!"; @Test - void testAmicableNumber() { + public void testShouldThrowExceptionWhenInvalidRangeProvided() { + checkInvalidRange(0, 0); + checkInvalidRange(0, 1); + checkInvalidRange(1, 0); + checkInvalidRange(10, -1); + checkInvalidRange(-1, 10); + } + + @Test + public void testShouldThrowExceptionWhenInvalidNumbersProvided() { + checkInvalidNumbers(0, 0); + checkInvalidNumbers(0, 1); + checkInvalidNumbers(1, 0); + } + + @Test + public void testAmicableNumbers() { assertThat(AmicableNumber.isAmicableNumber(220, 284)).isTrue(); assertThat(AmicableNumber.isAmicableNumber(1184, 1210)).isTrue(); assertThat(AmicableNumber.isAmicableNumber(2620, 2924)).isTrue(); } + + @Test + public void testShouldFindAllAmicableNumbersInRange() { + // given + var expectedResult = Set.of(Pair.of(220, 284), Pair.of(1184, 1210), Pair.of(2620, 2924)); + + // when + Set> result = AmicableNumber.findAllInRange(1, 3000); + + // then + Assertions.assertTrue(result.containsAll(expectedResult)); + } + + private static void checkInvalidRange(int from, int to) { + IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> AmicableNumber.findAllInRange(from, to)); + Assertions.assertEquals(exception.getMessage(), INVALID_RANGE_EXCEPTION_MESSAGE); + } + + private static void checkInvalidNumbers(int a, int b) { + IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> AmicableNumber.isAmicableNumber(a, b)); + Assertions.assertEquals(exception.getMessage(), INVALID_NUMBERS_EXCEPTION_MESSAGE); + } }