Repository: TheAlgorithms/Java
Pull request #4432 (2023-09-29 08:33:32)

Add `SecondMinMax`
### Description 
This PR provides a feature that contains the Java Program to find second largest / smallest element from the array with the most optimal solution

#### This PR addresses the Issue #4430 

<!-- For completed items, change [ ] to [x] -->

- [x] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md).
- [x] This pull request is all my own work -- I have not plagiarized it.
- [x] All filenames are in PascalCase.
- [x] All functions and variable names follow Java naming conventions.
- [x] All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.

#### I have read code of conduct and provided this PR accordingly


BharathSanjeeviT: Hey @vil02 , Thank you for looking into my contribution and suggesting all the changes. Hope I did correct all those you said 👍 
BharathSanjeeviT: Hey @vil02 , made the changes that you have mentioned and btw i thought *Commit Changes* would add extra commits, thanks for the information 👍 
BharathSanjeeviT: Hey @vil02 , made the changes that you've suggested 👍
BharathSanjeeviT: > Hey @vil02 , made the changes that you've suggested 👍



> Sorry for a _monster suggestion_: sometimes it is easier to express ideas just by writing code.

The changes you say, actually making me to learn new things, so i should thank you 👍 
BharathSanjeeviT: Hey @vil02 , the changes you have suggested are made, hope you merge this PR 👍 

Patch:
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 00000000..e5a2d3b8
--- /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<Integer, Integer> 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");
+        }
+    }
+}


Test patch:
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 00000000..c744614e
--- /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<Arguments> 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)));
+    }
+}