Skip to content

refactor: NextSmallerElement #5412

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 33 additions & 46 deletions src/main/java/com/thealgorithms/stacks/NextSmallerElement.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,70 +3,57 @@
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.
*
* <p>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.</p>
*
* <p>Example:</p>
* <pre>
* Input: {2, 7, 3, 5, 4, 6, 8}
* Output: [-1, 2, 2, 3, 3, 4, 6]
* </pre>
*/

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<Integer> stack = new Stack<>();

int[] result = new int[array.length];
Stack<Integer> 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));
return result;
}
}
Original file line number Diff line number Diff line change
@@ -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<Arguments> 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));
}
}