diff --git a/src/main/java/com/thealgorithms/stacks/NextSmallerElement.java b/src/main/java/com/thealgorithms/stacks/NextSmallerElement.java index 6eae06ad..254bb3b4 100644 --- a/src/main/java/com/thealgorithms/stacks/NextSmallerElement.java +++ b/src/main/java/com/thealgorithms/stacks/NextSmallerElement.java @@ -3,70 +3,57 @@ package com.thealgorithms.stacks; import java.util.Arrays; import java.util.Stack; -/* - Given an array "input" you need to print the first smaller element for each element to the left - side of an array. For a given element x of an array, the Next Smaller element of that element is - the first smaller element to the left side of it. If no such element is present print -1. - - Example - input = { 2, 7, 3, 5, 4, 6, 8 }; - At i = 0 - No elements to left of it : -1 - At i = 1 - Next smaller element between (0 , 0) is 2 - At i = 2 - Next smaller element between (0 , 1) is 2 - At i = 3 - Next smaller element between (0 , 2) is 3 - At i = 4 - Next smaller element between (0 , 3) is 3 - At i = 5 - Next smaller element between (0 , 4) is 4 - At i = 6 - Next smaller element between (0 , 5) is 6 - - result : [-1, 2, 2, 3, 3, 4, 6] - - 1) Create a new empty stack st - - 2) Iterate over array "input" , where "i" goes from 0 to input.length -1. - a) We are looking for value just smaller than `input[i]`. So keep popping from "stack" - till elements in "stack.peek() >= input[i]" or stack becomes empty. - b) If the stack is non-empty, then the top element is our previous element. Else the - previous element does not exist. c) push input[i] in stack. 3) If elements are left then their - answer is -1 +/** + * Utility class to find the next smaller element for each element in a given integer array. + * + *

The next smaller element for an element x is the first smaller element on the left side of x in the array. + * If no such element exists, the result will contain -1 for that position.

+ * + *

Example:

+ *
+ * Input:  {2, 7, 3, 5, 4, 6, 8}
+ * Output: [-1, 2, 2, 3, 3, 4, 6]
+ * 
*/ - public final class NextSmallerElement { private NextSmallerElement() { } + /** + * Finds the next smaller element for each element in the given array. + * + * @param array the input array of integers + * @return an array where each element is replaced by the next smaller element on the left side in the input array, + * or -1 if there is no smaller element. + * @throws IllegalArgumentException if the input array is null + */ public static int[] findNextSmallerElements(int[] array) { - // base case if (array == null) { - return array; + throw new IllegalArgumentException("Input array cannot be null"); } - Stack stack = new Stack<>(); + int[] result = new int[array.length]; + Stack stack = new Stack<>(); + + // Initialize all elements to -1 (in case there is no smaller element) Arrays.fill(result, -1); + // Traverse the array from left to right for (int i = 0; i < array.length; i++) { - while (!stack.empty() && stack.peek() >= array[i]) { + // Maintain the stack such that the top of the stack is the next smaller element + while (!stack.isEmpty() && stack.peek() >= array[i]) { stack.pop(); } - if (stack.empty()) { - result[i] = -1; - } else { + + // If stack is not empty, then the top is the next smaller element + if (!stack.isEmpty()) { result[i] = stack.peek(); } + + // Push the current element onto the stack stack.push(array[i]); } + return result; } - - public static void main(String[] args) { - int[] input = {2, 7, 3, 5, 4, 6, 8}; - int[] result = findNextSmallerElements(input); - System.out.println(Arrays.toString(result)); - } } diff --git a/src/test/java/com/thealgorithms/stacks/NextSmallerElementTest.java b/src/test/java/com/thealgorithms/stacks/NextSmallerElementTest.java new file mode 100644 index 00000000..62578baa --- /dev/null +++ b/src/test/java/com/thealgorithms/stacks/NextSmallerElementTest.java @@ -0,0 +1,29 @@ +package com.thealgorithms.stacks; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.stream.Stream; +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; + +class NextSmallerElementTest { + + @ParameterizedTest + @MethodSource("provideTestCases") + void testFindNextSmallerElements(int[] input, int[] expected) { + assertArrayEquals(expected, NextSmallerElement.findNextSmallerElements(input)); + } + + static Stream provideTestCases() { + return Stream.of(Arguments.of(new int[] {2, 7, 3, 5, 4, 6, 8}, new int[] {-1, 2, 2, 3, 3, 4, 6}), Arguments.of(new int[] {5}, new int[] {-1}), Arguments.of(new int[] {1, 2, 3, 4, 5}, new int[] {-1, 1, 2, 3, 4}), Arguments.of(new int[] {5, 4, 3, 2, 1}, new int[] {-1, -1, -1, -1, -1}), + Arguments.of(new int[] {4, 5, 2, 25}, new int[] {-1, 4, -1, 2}), Arguments.of(new int[] {}, new int[] {})); + } + + @Test + void testFindNextSmallerElementsExceptions() { + assertThrows(IllegalArgumentException.class, () -> NextSmallerElement.findNextSmallerElements(null)); + } +}