diff --git a/src/main/java/com/thealgorithms/maths/SecondMinMax.java b/src/main/java/com/thealgorithms/maths/SecondMinMax.java new file mode 100644 index 000000000000..e5a2d3b89085 --- /dev/null +++ b/src/main/java/com/thealgorithms/maths/SecondMinMax.java @@ -0,0 +1,60 @@ +package com.thealgorithms.maths; + +import java.util.function.BiPredicate; + +public final class SecondMinMax { + + /** + * Utility class for finding second maximum or minimum based on BiPredicate + * @exception IllegalArgumentException => if input array is of length less than 2 also if all elements are same + * @return the second minimum / maximum value from the input array + * @author Bharath Sanjeevi ( https://github.com/BharathSanjeeviT ) + */ + + private SecondMinMax() { + } + + private static int secondBest(final int[] arr, final int initialVal, final BiPredicate isBetter) { + checkInput(arr); + int best = initialVal; + int secBest = initialVal; + for (final int num : arr) { + if (isBetter.test(num, best)) { + secBest = best; + best = num; + } else if ((isBetter.test(num, secBest)) && (num != best)) { + secBest = num; + } + } + checkOutput(secBest, initialVal); + return secBest; + } + + /** + * @brief Finds the Second minimum / maximum value from the array + * @param arr the input array + * @exception IllegalArgumentException => if input array is of length less than 2 also if all elements are same + * @return the second minimum / maximum value from the input array + * @author Bharath Sanjeevi ( https://github.com/BharathSanjeeviT ) + */ + + public static int findSecondMin(final int[] arr) { + return secondBest(arr, Integer.MAX_VALUE, (a, b) -> a < b); + } + + public static int findSecondMax(final int[] arr) { + return secondBest(arr, Integer.MIN_VALUE, (a, b) -> a > b); + } + + private static void checkInput(final int[] arr) { + if (arr.length < 2) { + throw new IllegalArgumentException("Input array must have length of at least two"); + } + } + + private static void checkOutput(final int secNum, final int initialVal) { + if (secNum == initialVal) { + throw new IllegalArgumentException("Input array should have at least 2 distinct elements"); + } + } +} diff --git a/src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java b/src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java new file mode 100644 index 000000000000..c744614e5cfa --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java @@ -0,0 +1,58 @@ +package com.thealgorithms.maths; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.stream.Stream; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class SecondMinMaxTest { + + private static final String EXP_MSG_ARR_LEN_LESS_2 = "Input array must have length of at least two"; + private static final String EXP_MSG_ARR_SAME_ELE = "Input array should have at least 2 distinct elements"; + + public static class TestCase { + public TestCase(final int[] inInputArray, final int inSecondMin, final int inSecondMax) { + inputArray = inInputArray; + secondMin = inSecondMin; + secondMax = inSecondMax; + } + final int[] inputArray; + final int secondMin; + final int secondMax; + } + + @Test + public void testForEmptyInputArray() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> SecondMinMax.findSecondMin(new int[] {})); + assertEquals(exception.getMessage(), EXP_MSG_ARR_LEN_LESS_2); + } + + @Test + public void testForArrayWithSingleElement() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> SecondMinMax.findSecondMax(new int[] {1})); + assertEquals(exception.getMessage(), EXP_MSG_ARR_LEN_LESS_2); + } + + @Test + public void testForArrayWithSameElements() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> SecondMinMax.findSecondMin(new int[] {1, 1, 1, 1})); + assertEquals(exception.getMessage(), EXP_MSG_ARR_SAME_ELE); + } + + @ParameterizedTest + @MethodSource("inputStream") + void numberTests(final TestCase tc) { + Assertions.assertEquals(tc.secondMax, SecondMinMax.findSecondMax(tc.inputArray)); + Assertions.assertEquals(tc.secondMin, SecondMinMax.findSecondMin(tc.inputArray)); + } + + private static Stream inputStream() { + return Stream.of(Arguments.of(new TestCase(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 2, 9)), Arguments.of(new TestCase(new int[] {5, 4, 5, 5, 5}, 5, 4)), Arguments.of(new TestCase(new int[] {-1, 0}, 0, -1)), + Arguments.of(new TestCase(new int[] {-10, -9, -8, -7, -6, -5, -4, -3, -2, -1}, -9, -2)), Arguments.of(new TestCase(new int[] {3, -2, 3, 9, -4, -4, 8}, -2, 8))); + } +}