From 04672018c5edd950a446b44716a02cbfa2e88835 Mon Sep 17 00:00:00 2001 From: Tapan Avasthi Date: Tue, 30 Jul 2019 16:03:25 +0530 Subject: [PATCH] BAEL-3116: Finding the Least Common Multiple in Java - Add tutorial to implement algorithms used for computing LCM of two or more numbers. - List of Algorithms covered: - Simple Method - Prime Factorization Method - Euclidean Algorithm - BigInteger Class for large numbers - Lambda Implementation for LCM of more than two numbers - Reference: BAEL-3116 --- .../java/com/baeldung/lcm/BigIntegerLCM.java | 13 ++++++ .../com/baeldung/lcm/EuclideanAlgorithm.java | 40 ++++++++++++++++++ .../lcm/PrimeFactorizationAlgorithm.java | 42 +++++++++++++++++++ .../com/baeldung/lcm/SimpleAlgorithm.java | 18 ++++++++ .../baeldung/lcm/BigIntegerLCMUnitTest.java | 18 ++++++++ .../lcm/EuclideanAlgorithmUnitTest.java | 27 ++++++++++++ .../PrimeFactorizationAlgorithmUnitTest.java | 30 +++++++++++++ .../baeldung/lcm/SimpleAlgorithmUnitTest.java | 15 +++++++ 8 files changed, 203 insertions(+) create mode 100644 java-numbers-2/src/main/java/com/baeldung/lcm/BigIntegerLCM.java create mode 100644 java-numbers-2/src/main/java/com/baeldung/lcm/EuclideanAlgorithm.java create mode 100644 java-numbers-2/src/main/java/com/baeldung/lcm/PrimeFactorizationAlgorithm.java create mode 100644 java-numbers-2/src/main/java/com/baeldung/lcm/SimpleAlgorithm.java create mode 100644 java-numbers-2/src/test/java/com/baeldung/lcm/BigIntegerLCMUnitTest.java create mode 100644 java-numbers-2/src/test/java/com/baeldung/lcm/EuclideanAlgorithmUnitTest.java create mode 100644 java-numbers-2/src/test/java/com/baeldung/lcm/PrimeFactorizationAlgorithmUnitTest.java create mode 100644 java-numbers-2/src/test/java/com/baeldung/lcm/SimpleAlgorithmUnitTest.java diff --git a/java-numbers-2/src/main/java/com/baeldung/lcm/BigIntegerLCM.java b/java-numbers-2/src/main/java/com/baeldung/lcm/BigIntegerLCM.java new file mode 100644 index 0000000000..affface9c0 --- /dev/null +++ b/java-numbers-2/src/main/java/com/baeldung/lcm/BigIntegerLCM.java @@ -0,0 +1,13 @@ +package com.baeldung.lcm; + +import java.math.BigInteger; + +public class BigIntegerLCM { + + public static BigInteger lcm(BigInteger number1, BigInteger number2) { + BigInteger gcd = number1.gcd(number2); + BigInteger absProduct = number1.multiply(number2).abs(); + return absProduct.divide(gcd); + } + +} diff --git a/java-numbers-2/src/main/java/com/baeldung/lcm/EuclideanAlgorithm.java b/java-numbers-2/src/main/java/com/baeldung/lcm/EuclideanAlgorithm.java new file mode 100644 index 0000000000..4032d119fa --- /dev/null +++ b/java-numbers-2/src/main/java/com/baeldung/lcm/EuclideanAlgorithm.java @@ -0,0 +1,40 @@ +package com.baeldung.lcm; + +import java.util.Arrays; + +public class EuclideanAlgorithm { + + public static int gcd(int number1, int number2) { + if (number1 == 0 || number2 == 0) { + return number1 + number2; + } else { + int absNumber1 = Math.abs(number1); + int absNumber2 = Math.abs(number2); + int biggerValue = Math.max(absNumber1, absNumber2); + int smallerValue = Math.min(absNumber1, absNumber2); + return gcd(biggerValue % smallerValue, smallerValue); + } + } + + public static int lcm(int number1, int number2) { + if (number1 == 0 || number2 == 0) + return 0; + else { + int gcd = gcd(number1, number2); + return Math.abs(number1 * number2) / gcd; + } + } + + public static int lcmForArray(int[] numbers) { + int lcm = numbers[0]; + for (int i = 1; i <= numbers.length - 1; i++) { + lcm = lcm(lcm, numbers[i]); + } + return lcm; + } + + public static int lcmByLambda(int... numbers) { + return Arrays.stream(numbers).reduce(1, (lcmSoFar, currentNumber) -> Math.abs(lcmSoFar * currentNumber) / gcd(lcmSoFar, currentNumber)); + } + +} diff --git a/java-numbers-2/src/main/java/com/baeldung/lcm/PrimeFactorizationAlgorithm.java b/java-numbers-2/src/main/java/com/baeldung/lcm/PrimeFactorizationAlgorithm.java new file mode 100644 index 0000000000..cfdc3bfe96 --- /dev/null +++ b/java-numbers-2/src/main/java/com/baeldung/lcm/PrimeFactorizationAlgorithm.java @@ -0,0 +1,42 @@ +package com.baeldung.lcm; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class PrimeFactorizationAlgorithm { + + public static Map getPrimeFactors(int number) { + int absNumber = Math.abs(number); + Map primeFactorsMap = new HashMap(); + for (int factor = 2; factor <= absNumber; factor++) { + while (absNumber % factor == 0) { + Integer power = primeFactorsMap.get(factor); + if (power == null) { + power = 0; + } + primeFactorsMap.put(factor, power + 1); + absNumber /= factor; + } + } + return primeFactorsMap; + } + + public static int lcm(int number1, int number2) { + if (number1 == 0 || number2 == 0) { + return 0; + } + Map primeFactorsForNum1 = getPrimeFactors(number1); + Map primeFactorsForNum2 = getPrimeFactors(number2); + Set primeFactorsUnionSet = new HashSet(primeFactorsForNum1.keySet()); + primeFactorsUnionSet.addAll(primeFactorsForNum2.keySet()); + int lcm = 1; + for (Integer primeFactor : primeFactorsUnionSet) { + lcm *= Math.pow(primeFactor, Math.max(primeFactorsForNum1.getOrDefault(primeFactor, 0), + primeFactorsForNum2.getOrDefault(primeFactor, 0))); + } + return lcm; + } + +} diff --git a/java-numbers-2/src/main/java/com/baeldung/lcm/SimpleAlgorithm.java b/java-numbers-2/src/main/java/com/baeldung/lcm/SimpleAlgorithm.java new file mode 100644 index 0000000000..6ba4966dc7 --- /dev/null +++ b/java-numbers-2/src/main/java/com/baeldung/lcm/SimpleAlgorithm.java @@ -0,0 +1,18 @@ +package com.baeldung.lcm; + +public class SimpleAlgorithm { + public static int lcm(int number1, int number2) { + if (number1 == 0 || number2 == 0) { + return 0; + } + int absNumber1 = Math.abs(number1); + int absNumber2 = Math.abs(number2); + int absHigherNumber = Math.max(absNumber1, absNumber2); + int absLowerNumber = Math.min(absNumber1, absNumber2); + int lcm = absHigherNumber; + while (lcm % absLowerNumber != 0) { + lcm += absHigherNumber; + } + return lcm; + } +} diff --git a/java-numbers-2/src/test/java/com/baeldung/lcm/BigIntegerLCMUnitTest.java b/java-numbers-2/src/test/java/com/baeldung/lcm/BigIntegerLCMUnitTest.java new file mode 100644 index 0000000000..10bee4c087 --- /dev/null +++ b/java-numbers-2/src/test/java/com/baeldung/lcm/BigIntegerLCMUnitTest.java @@ -0,0 +1,18 @@ +package com.baeldung.lcm; + + +import org.junit.Assert; +import org.junit.Test; + +import java.math.BigInteger; + +public class BigIntegerLCMUnitTest { + + @Test + public void testLCM() { + BigInteger number1 = new BigInteger("12"); + BigInteger number2 = new BigInteger("18"); + BigInteger expectedLCM = new BigInteger("36"); + Assert.assertEquals(expectedLCM, BigIntegerLCM.lcm(number1, number2)); + } +} diff --git a/java-numbers-2/src/test/java/com/baeldung/lcm/EuclideanAlgorithmUnitTest.java b/java-numbers-2/src/test/java/com/baeldung/lcm/EuclideanAlgorithmUnitTest.java new file mode 100644 index 0000000000..09a53cfa4e --- /dev/null +++ b/java-numbers-2/src/test/java/com/baeldung/lcm/EuclideanAlgorithmUnitTest.java @@ -0,0 +1,27 @@ +package com.baeldung.lcm; + +import org.junit.Assert; +import org.junit.Test; + +public class EuclideanAlgorithmUnitTest { + + @Test + public void testGCD() { + Assert.assertEquals(6, EuclideanAlgorithm.gcd(12, 18)); + } + + @Test + public void testLCM() { + Assert.assertEquals(36, EuclideanAlgorithm.lcm(12, 18)); + } + + @Test + public void testLCMForArray() { + Assert.assertEquals(15, EuclideanAlgorithm.lcmForArray(new int[]{3, 5, 15})); + } + + @Test + public void testLCMByLambdaForArray() { + Assert.assertEquals(15, EuclideanAlgorithm.lcmByLambda(new int[]{3, 5, 15})); + } +} diff --git a/java-numbers-2/src/test/java/com/baeldung/lcm/PrimeFactorizationAlgorithmUnitTest.java b/java-numbers-2/src/test/java/com/baeldung/lcm/PrimeFactorizationAlgorithmUnitTest.java new file mode 100644 index 0000000000..b33b81f85e --- /dev/null +++ b/java-numbers-2/src/test/java/com/baeldung/lcm/PrimeFactorizationAlgorithmUnitTest.java @@ -0,0 +1,30 @@ +package com.baeldung.lcm; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static com.baeldung.lcm.PrimeFactorizationAlgorithm.*; + + +public class PrimeFactorizationAlgorithmUnitTest { + + @Test + public void testGetPrimeFactors() { + Map expectedPrimeFactorsMapForTwelve = new HashMap<>(); + expectedPrimeFactorsMapForTwelve.put(2, 2); + expectedPrimeFactorsMapForTwelve.put(3, 1); + Map expectedPrimeFactorsMapForEighteen = new HashMap<>(); + expectedPrimeFactorsMapForEighteen.put(2, 1); + expectedPrimeFactorsMapForEighteen.put(3, 2); + Assert.assertEquals(expectedPrimeFactorsMapForTwelve, getPrimeFactors(12)); + Assert.assertEquals(expectedPrimeFactorsMapForEighteen, getPrimeFactors(18)); + } + + @Test + public void testLCM() { + Assert.assertEquals(36, PrimeFactorizationAlgorithm.lcm(12, 18)); + } +} diff --git a/java-numbers-2/src/test/java/com/baeldung/lcm/SimpleAlgorithmUnitTest.java b/java-numbers-2/src/test/java/com/baeldung/lcm/SimpleAlgorithmUnitTest.java new file mode 100644 index 0000000000..bc0a1690f4 --- /dev/null +++ b/java-numbers-2/src/test/java/com/baeldung/lcm/SimpleAlgorithmUnitTest.java @@ -0,0 +1,15 @@ +package com.baeldung.lcm; + +import org.junit.Assert; +import org.junit.Test; + +import static com.baeldung.lcm.SimpleAlgorithm.*; + +public class SimpleAlgorithmUnitTest { + + @Test + public void testLCM() { + Assert.assertEquals(36, lcm(12, 18)); + } + +}