Skip to content

Commit 36a7dd6

Browse files
authoredOct 3, 2024
Add BalancedParenthesesChecker, NextGreaterElement, and ReverseStack (#473)
1 parent cf19352 commit 36a7dd6

7 files changed

+493
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
using System;
2+
using Algorithms.Stack;
3+
using NUnit.Framework;
4+
5+
namespace Algorithms.Tests.Stack
6+
{
7+
[TestFixture]
8+
public class BalancedParenthesesCheckerTests
9+
{
10+
public static bool IsBalanced(string expression)
11+
{
12+
var checker = new BalancedParenthesesChecker();
13+
return checker.IsBalanced(expression);
14+
}
15+
16+
[Test]
17+
public void IsBalanced_EmptyString_ThrowsArgumentException()
18+
{
19+
// Arrange
20+
var expression = string.Empty;
21+
22+
// Act & Assert
23+
var ex = Assert.Throws<ArgumentException>(() => IsBalanced(expression));
24+
25+
if(ex!=null)
26+
{
27+
Assert.That(ex.Message, Is.EqualTo("The input expression cannot be null or empty."));
28+
}
29+
30+
}
31+
32+
[Test]
33+
public void IsBalanced_ValidBalancedExpression_ReturnsTrue()
34+
{
35+
// Arrange
36+
var expression = "{[()]}";
37+
38+
// Act
39+
var result = IsBalanced(expression);
40+
41+
// Assert
42+
Assert.That(result, Is.EqualTo(true));
43+
}
44+
45+
[Test]
46+
public void IsBalanced_ValidUnbalancedExpression_ReturnsFalse()
47+
{
48+
// Arrange
49+
var expression = "{[(])}";
50+
51+
// Act
52+
var result = IsBalanced(expression);
53+
54+
// Assert
55+
Assert.That(result, Is.EqualTo(false));
56+
}
57+
58+
[Test]
59+
public void IsBalanced_UnbalancedWithExtraClosingBracket_ReturnsFalse()
60+
{
61+
// Arrange
62+
var expression = "{[()]}]";
63+
64+
// Act
65+
var result = IsBalanced(expression);
66+
67+
// Assert
68+
Assert.That(result, Is.EqualTo(false));
69+
}
70+
71+
[Test]
72+
public void IsBalanced_ExpressionWithInvalidCharacters_ThrowsArgumentException()
73+
{
74+
// Arrange
75+
var expression = "{[a]}";
76+
77+
// Act & Assert
78+
var ex = Assert.Throws<ArgumentException>(() => IsBalanced(expression));
79+
if (ex != null)
80+
{
81+
Assert.That(ex.Message, Is.EqualTo("Invalid character 'a' found in the expression."));
82+
}
83+
}
84+
85+
[Test]
86+
public void IsBalanced_SingleOpeningBracket_ReturnsFalse()
87+
{
88+
// Arrange
89+
var expression = "(";
90+
91+
// Act
92+
var result = IsBalanced(expression);
93+
94+
// Assert
95+
Assert.That(result, Is.EqualTo(false));
96+
}
97+
98+
[Test]
99+
public void IsBalanced_SingleClosingBracket_ReturnsFalse()
100+
{
101+
// Arrange
102+
var expression = ")";
103+
104+
// Act
105+
var result = IsBalanced(expression);
106+
107+
// Assert
108+
Assert.That(result, Is.EqualTo(false));
109+
}
110+
111+
[Test]
112+
public void IsBalanced_ExpressionWithMultipleBalancedBrackets_ReturnsTrue()
113+
{
114+
// Arrange
115+
var expression = "[{()}]()";
116+
117+
// Act
118+
var result = IsBalanced(expression);
119+
120+
// Assert
121+
Assert.That(result, Is.EqualTo(true));
122+
}
123+
}
124+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
using System;
2+
using Algorithms.Stack;
3+
using NUnit.Framework;
4+
5+
namespace Algorithms.Tests.Stack
6+
{
7+
[TestFixture]
8+
public class NextGreaterElementTests
9+
{
10+
private static int[] FindNextGreaterElement(int[] input)
11+
{
12+
var obj = new NextGreaterElement();
13+
return obj.FindNextGreaterElement(input);
14+
}
15+
16+
[Test]
17+
public void FindNextGreaterElement_InputIsEmpty_ReturnsEmptyArray()
18+
{
19+
// Arrange
20+
int[] input = Array.Empty<int>();
21+
int[] expected = Array.Empty<int>();
22+
23+
// Act
24+
var result = FindNextGreaterElement(input);
25+
26+
// Assert
27+
Assert.That(result, Is.EqualTo(expected));
28+
}
29+
30+
[Test]
31+
public void FindNextGreaterElement_BasicScenario_ReturnsCorrectResult()
32+
{
33+
// Arrange
34+
int[] input = { 4, 5, 2, 25 };
35+
int[] expected = { 5, 25, 25, -1 };
36+
37+
// Act
38+
var result = FindNextGreaterElement(input);
39+
40+
// Assert
41+
Assert.That(result, Is.EqualTo(expected));
42+
}
43+
44+
[Test]
45+
public void FindNextGreaterElement_NoNextGreaterElement_ReturnsCorrectResult()
46+
{
47+
// Arrange
48+
int[] input = { 13, 7, 6, 12 };
49+
int[] expected = { -1, 12, 12, -1 };
50+
51+
// Act
52+
var result = FindNextGreaterElement(input);
53+
54+
// Assert
55+
Assert.That(result, Is.EqualTo(expected));
56+
}
57+
58+
[Test]
59+
public void FindNextGreaterElement_AllElementsHaveNoGreaterElement_ReturnsAllNegativeOnes()
60+
{
61+
// Arrange
62+
int[] input = { 5, 4, 3, 2, 1 };
63+
int[] expected = { -1, -1, -1, -1, -1 };
64+
65+
// Act
66+
var result = FindNextGreaterElement(input);
67+
68+
// Assert
69+
Assert.That(result, Is.EqualTo(expected));
70+
}
71+
72+
[Test]
73+
public void FindNextGreaterElement_InputWithDuplicates_ReturnsCorrectResult()
74+
{
75+
// Arrange
76+
int[] input = { 4, 4, 3, 2, 4 };
77+
int[] expected = { -1, -1, 4, 4, -1 };
78+
79+
// Act
80+
var result = FindNextGreaterElement(input);
81+
82+
// Assert
83+
Assert.That(result, Is.EqualTo(expected));
84+
}
85+
86+
[Test]
87+
public void FindNextGreaterElement_SingleElementArray_ReturnsNegativeOne()
88+
{
89+
// Arrange
90+
int[] input = { 10 };
91+
int[] expected = { -1 };
92+
93+
// Act
94+
var result = FindNextGreaterElement(input);
95+
96+
// Assert
97+
Assert.That(result, Is.EqualTo(expected));
98+
}
99+
}
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using Algorithms.Stack;
2+
using NUnit.Framework;
3+
using System.Collections.Generic;
4+
5+
6+
namespace Algorithms.Tests.Stack
7+
{
8+
public class ReverseStackTests
9+
{
10+
public static void Reverse<T>(Stack<T> stack)
11+
{
12+
var obj = new ReverseStack();
13+
obj.Reverse(stack);
14+
}
15+
16+
[Test]
17+
public void Reverse_EmptyStack_DoesNotChangeStack()
18+
{
19+
// Arrange
20+
Stack<int> stack = new Stack<int>();
21+
22+
// Act
23+
Reverse(stack);
24+
25+
// Assert
26+
Assert.That(stack.Count, Is.EqualTo(0));
27+
}
28+
29+
[Test]
30+
public void Reverse_SingleElementStack_DoesNotChangeStack()
31+
{
32+
// Arrange
33+
Stack<int> stack = new Stack<int>();
34+
stack.Push(1);
35+
36+
// Act
37+
Reverse(stack);
38+
39+
// Assert
40+
Assert.That(stack.Count, Is.EqualTo(1));
41+
Assert.That(stack.Peek(), Is.EqualTo(1));
42+
}
43+
44+
[Test]
45+
public void Reverse_MultipleElementStack_ReturnsCorrectOrder()
46+
{
47+
// Arrange
48+
Stack<int> stack = new Stack<int>();
49+
stack.Push(1);
50+
stack.Push(2);
51+
stack.Push(3);
52+
// The stack is now [3, 2, 1] (top to bottom)
53+
54+
// Act
55+
Reverse(stack);
56+
57+
// Assert
58+
Assert.That(stack.Count, Is.EqualTo(3));
59+
Assert.That(stack.Pop(), Is.EqualTo(1)); // Should return 1
60+
Assert.That(stack.Pop(), Is.EqualTo(2)); // Should return 2
61+
Assert.That(stack.Pop(), Is.EqualTo(3)); // Should return 3
62+
}
63+
64+
[Test]
65+
public void Reverse_StackWithDuplicates_ReturnsCorrectOrder()
66+
{
67+
// Arrange
68+
Stack<int> stack = new Stack<int>();
69+
stack.Push(1);
70+
stack.Push(2);
71+
stack.Push(1);
72+
// The stack is now [1, 2, 1] (top to bottom)
73+
74+
// Act
75+
Reverse(stack);
76+
77+
// Assert
78+
Assert.That(stack.Count, Is.EqualTo(3));
79+
Assert.That(stack.Pop(), Is.EqualTo(1)); // Should return 1
80+
Assert.That(stack.Pop(), Is.EqualTo(2)); // Should return 2
81+
Assert.That(stack.Pop(), Is.EqualTo(1)); // Should return 1
82+
}
83+
}
84+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace Algorithms.Stack
5+
{
6+
/// <summary>
7+
/// It checks if an expression has matching and balanced parentheses.
8+
/// @author Mohit Singh. <a href="https://github.com/mohit-gogitter">mohit-gogitter</a>
9+
/// </summary>
10+
public class BalancedParenthesesChecker
11+
{
12+
private static readonly Dictionary<char, char> ParenthesesMap = new Dictionary<char, char>
13+
{
14+
{ '(', ')' },
15+
{ '{', '}' },
16+
{ '[', ']' },
17+
};
18+
19+
/// <summary>
20+
/// Determines if a given string expression containing brackets is balanced.
21+
/// A string is considered balanced if all opening brackets have corresponding closing brackets
22+
/// in the correct order. The supported brackets are '()', '{}', and '[]'.
23+
/// </summary>
24+
/// <param name="expression">
25+
/// The input string expression containing the brackets to check for balance.
26+
/// </param>
27+
/// <returns>
28+
/// <c>true</c> if the brackets in the expression are balanced; otherwise, <c>false</c>.
29+
/// </returns>
30+
/// <exception cref="ArgumentException">
31+
/// Thrown when the input expression contains invalid characters or is null/empty.
32+
/// Only '(', ')', '{', '}', '[', ']' characters are allowed.
33+
/// </exception>
34+
public bool IsBalanced(string expression)
35+
{
36+
if (string.IsNullOrEmpty(expression))
37+
{
38+
throw new ArgumentException("The input expression cannot be null or empty.");
39+
}
40+
41+
Stack<char> stack = new Stack<char>();
42+
foreach (char c in expression)
43+
{
44+
if (IsOpeningParenthesis(c))
45+
{
46+
stack.Push(c);
47+
}
48+
else if (IsClosingParenthesis(c))
49+
{
50+
if (!IsBalancedClosing(stack, c))
51+
{
52+
return false;
53+
}
54+
}
55+
else
56+
{
57+
throw new ArgumentException($"Invalid character '{c}' found in the expression.");
58+
}
59+
}
60+
61+
return stack.Count == 0;
62+
}
63+
64+
private static bool IsOpeningParenthesis(char c)
65+
{
66+
return c == '(' || c == '{' || c == '[';
67+
}
68+
69+
private static bool IsClosingParenthesis(char c)
70+
{
71+
return c == ')' || c == '}' || c == ']';
72+
}
73+
74+
private static bool IsBalancedClosing(Stack<char> stack, char close)
75+
{
76+
if (stack.Count == 0)
77+
{
78+
return false;
79+
}
80+
81+
char open = stack.Pop();
82+
return IsMatchingPair(open, close);
83+
}
84+
85+
private static bool IsMatchingPair(char open, char close)
86+
{
87+
return ParenthesesMap.ContainsKey(open) && ParenthesesMap[open] == close;
88+
}
89+
}
90+
}
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace Algorithms.Stack
5+
{
6+
/// <summary>
7+
/// For each element in an array, the utility finds the next greater element on the right side using a stack.
8+
/// @author Mohit Singh. <a href="https://github.com/mohit-gogitter">mohit-gogitter</a>
9+
/// </summary>
10+
public class NextGreaterElement
11+
{
12+
/// <summary>
13+
/// Finds the next greater element for each element in the input array.
14+
/// The next greater element for an element x is the first element greater than x to its right.
15+
/// If there is no greater element, -1 is returned for that element.
16+
/// </summary>
17+
/// <param name="nums">The array of integers to find the next greater elements for.</param>
18+
/// <returns>An array where each index contains the next greater element of the corresponding element in the input array, or -1 if no such element exists.</returns>
19+
/// <exception cref="ArgumentNullException">Thrown when the input array is null.</exception>
20+
public int[] FindNextGreaterElement(int[] nums)
21+
{
22+
int[] result = new int[nums.Length];
23+
Stack<int> stack = new Stack<int>();
24+
25+
// Initialize all elements in the result array to -1
26+
for (int i = 0; i < nums.Length; i++)
27+
{
28+
result[i] = -1;
29+
}
30+
31+
for (int i = 0; i < nums.Length; i++)
32+
{
33+
// While the stack is not empty and the current element is greater than the element
34+
// corresponding to the index stored at the top of the stack
35+
while (stack.Count > 0 && nums[i] > nums[stack.Peek()])
36+
{
37+
int index = stack.Pop();
38+
result[index] = nums[i]; // Set the next greater element
39+
}
40+
41+
stack.Push(i); // Push current index to stack
42+
}
43+
44+
return result;
45+
}
46+
}
47+
}

‎Algorithms/Stack/ReverseStack.cs

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace Algorithms.Stack
5+
{
6+
/// <summary>
7+
/// Reverses the elements in a stack using recursion.
8+
/// @author Mohit Singh. <a href="https://github.com/mohit-gogitter">mohit-gogitter</a>
9+
/// </summary>
10+
public class ReverseStack
11+
{
12+
/// <summary>
13+
/// Recursively reverses the elements of the specified stack.
14+
/// </summary>
15+
/// <typeparam name="T">The type of elements in the stack.</typeparam>
16+
/// <param name="stack">The stack to be reversed. This parameter cannot be null.</param>
17+
/// <exception cref="ArgumentNullException">Thrown when the stack parameter is null.</exception>
18+
public void Reverse<T>(Stack<T> stack)
19+
{
20+
if (stack.Count == 0)
21+
{
22+
return;
23+
}
24+
25+
T temp = stack.Pop();
26+
Reverse(stack);
27+
InsertAtBottom(stack, temp);
28+
}
29+
30+
private void InsertAtBottom<T>(Stack<T> stack, T value)
31+
{
32+
if (stack.Count == 0)
33+
{
34+
stack.Push(value);
35+
}
36+
else
37+
{
38+
T temp = stack.Pop();
39+
InsertAtBottom(stack, value);
40+
stack.Push(temp);
41+
}
42+
}
43+
}
44+
}

‎README.md

+4
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ find more than one implementation for the same objective but using different alg
179179
* [A057588 Kummer Numbers](./Algorithms/Sequences/KummerNumbersSequence.cs)
180180
* [A019434 Fermat Primes](./Algorithms/Sequences/FermatPrimesSequence.cs)
181181
* [A181391 Van Eck's](./Algorithms/Sequences/VanEcksSequence.cs)
182+
* [Stack](./Algorithms/Stack)
183+
* [Next Greater Element](./Algorithms/Stack/NextGreaterElement.cs)
184+
* [Balanced Parentheses Checker](./Algorithms/Stack/BalancedParenthesesChecker.cs)
185+
* [Reverse Stack](./Algorithms/Stack/ReverseStack.cs)
182186
* [String](./Algorithms/Strings)
183187
* [Similarity](./Algorithms/Strings/Similarity/)
184188
* [Cosine Similarity](./Algorithms/Strings/Similarity/CosineSimilarity.cs)

0 commit comments

Comments
 (0)