diff --git a/DIRECTORY.md b/DIRECTORY.md index 265d1aeeb893..6073904a745e 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -431,6 +431,7 @@ * [StrobogrammaticNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/StrobogrammaticNumber.java) * [SumOfArithmeticSeries](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SumOfArithmeticSeries.java) * [SumOfDigits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SumOfDigits.java) + * [SumOfOddNumbers](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SumOfOddNumbers.java) * [SumWithoutArithmeticOperators](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SumWithoutArithmeticOperators.java) * [TrinomialTriangle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/TrinomialTriangle.java) * [TwinPrime](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/TwinPrime.java) @@ -612,6 +613,7 @@ * [InfixToPrefix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/InfixToPrefix.java) * [LargestRectangle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/LargestRectangle.java) * [MaximumMinimumWindow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/MaximumMinimumWindow.java) + * [MinStackUsingSingleStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/MinStackUsingSingleStack.java) * [NextGreaterElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/NextGreaterElement.java) * [NextSmallerElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/NextSmallerElement.java) * [PostfixEvaluator](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/PostfixEvaluator.java) @@ -1009,6 +1011,7 @@ * [StrobogrammaticNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/StrobogrammaticNumberTest.java) * [SumOfArithmeticSeriesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SumOfArithmeticSeriesTest.java) * [SumOfDigitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SumOfDigitsTest.java) + * [SumOfOddNumbersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SumOfOddNumbersTest.java) * [SumWithoutArithmeticOperatorsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SumWithoutArithmeticOperatorsTest.java) * [TestArmstrong](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/TestArmstrong.java) * [TwinPrimeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/TwinPrimeTest.java) @@ -1164,6 +1167,7 @@ * [InfixToPostfixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/InfixToPostfixTest.java) * [InfixToPrefixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java) * [LargestRectangleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java) + * [MinStackUsingSingleStackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/MinStackUsingSingleStackTest.java) * [NextGreaterElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/NextGreaterElementTest.java) * [NextSmallerElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/NextSmallerElementTest.java) * [PostfixEvaluatorTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/PostfixEvaluatorTest.java) diff --git a/src/main/java/com/thealgorithms/stacks/MinStackUsingSingleStack.java b/src/main/java/com/thealgorithms/stacks/MinStackUsingSingleStack.java new file mode 100644 index 000000000000..f5e526b102cf --- /dev/null +++ b/src/main/java/com/thealgorithms/stacks/MinStackUsingSingleStack.java @@ -0,0 +1,65 @@ +package com.thealgorithms.stacks; + +import java.util.EmptyStackException; +import java.util.Stack; + +/** + * Min-Stack implementation using a single stack. + * + * This stack supports push, pop, and retrieving the minimum element + * in constant time (O(1)) using a modified approach where the stack + * stores both the element and the minimum value so far. + * + * @author Hardvan + */ +public class MinStackUsingSingleStack { + private final Stack stack = new Stack<>(); + + /** + * Pushes a new value onto the stack. + * Each entry stores both the value and the minimum value so far. + * + * @param value The value to be pushed onto the stack. + */ + public void push(int value) { + if (stack.isEmpty()) { + stack.push(new long[] {value, value}); + } else { + long minSoFar = Math.min(value, stack.peek()[1]); + stack.push(new long[] {value, minSoFar}); + } + } + + /** + * Removes the top element from the stack. + */ + public void pop() { + if (!stack.isEmpty()) { + stack.pop(); + } + } + + /** + * Retrieves the top element from the stack. + * + * @return The top element of the stack. + */ + public int top() { + if (!stack.isEmpty()) { + return (int) stack.peek()[0]; + } + throw new EmptyStackException(); + } + + /** + * Retrieves the minimum element in the stack. + * + * @return The minimum element so far. + */ + public int getMin() { + if (!stack.isEmpty()) { + return (int) stack.peek()[1]; + } + throw new EmptyStackException(); + } +} diff --git a/src/test/java/com/thealgorithms/stacks/MinStackUsingSingleStackTest.java b/src/test/java/com/thealgorithms/stacks/MinStackUsingSingleStackTest.java new file mode 100644 index 000000000000..90887294638f --- /dev/null +++ b/src/test/java/com/thealgorithms/stacks/MinStackUsingSingleStackTest.java @@ -0,0 +1,66 @@ +package com.thealgorithms.stacks; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.EmptyStackException; +import org.junit.jupiter.api.Test; + +public class MinStackUsingSingleStackTest { + + @Test + public void testBasicOperations() { + MinStackUsingSingleStack minStack = new MinStackUsingSingleStack(); + + minStack.push(3); + minStack.push(5); + assertEquals(3, minStack.getMin(), "Minimum should be 3"); + + minStack.push(2); + minStack.push(1); + assertEquals(1, minStack.getMin(), "Minimum should be 1"); + + minStack.pop(); + assertEquals(2, minStack.getMin(), "Minimum should be 2"); + + minStack.pop(); + assertEquals(3, minStack.getMin(), "Minimum should be 3"); + } + + @Test + public void testTopElement() { + MinStackUsingSingleStack minStack = new MinStackUsingSingleStack(); + + minStack.push(8); + minStack.push(10); + assertEquals(10, minStack.top(), "Top element should be 10"); + + minStack.pop(); + assertEquals(8, minStack.top(), "Top element should be 8"); + } + + @Test + public void testGetMinAfterPops() { + MinStackUsingSingleStack minStack = new MinStackUsingSingleStack(); + + minStack.push(5); + minStack.push(3); + minStack.push(7); + + assertEquals(3, minStack.getMin(), "Minimum should be 3"); + + minStack.pop(); // Popping 7 + assertEquals(3, minStack.getMin(), "Minimum should still be 3"); + + minStack.pop(); // Popping 3 + assertEquals(5, minStack.getMin(), "Minimum should now be 5"); + } + + @Test + public void testEmptyStack() { + MinStackUsingSingleStack minStack = new MinStackUsingSingleStack(); + + assertThrows(EmptyStackException.class, minStack::top, "Should throw exception on top()"); + assertThrows(EmptyStackException.class, minStack::getMin, "Should throw exception on getMin()"); + } +}