Difficulty: Medium, Asked-In: Amazon, Adobe, Hike
Key takeaway: An excellent problem to learn problem solving using the stack data structure.
Given an expression string containing opening and closing parentheses, write a program to check if the expression is a balanced expression or not. An expression is balanced if each opening parenthesis is closed by the same type of closing parenthesis in the exact same order.
Input: exp[] = "[ ( ) ] { } { ( ) ( ) }", Output: Balanced
Explanation: The expression is balanced because all the parentheses are well-formed.
Input: exp[] = "[ ( ] )" Output: Not Balanced
Explanation: The expression is not balanced because there is a closing parenthesis ']' after the opening parenthesis '('.
If we observe the order of parentheses in a correct expression, we can visualize a Last-In-First-Out (LIFO) structure: the opening parenthesis that comes last will have the corresponding closing parenthesis come first in the expression. So, we can use stack to validate the correct order of parentheses in the expression.
The idea is to use a stack to keep track of opening parentheses. In other words, when we encounter an opening parenthesis, we push it into the stack. If we encounter a closing parenthesis, we check if the top element of the stack is the corresponding opening parenthesis. If the stack is empty or the parentheses don't match, the expression is not balanced. Finally, after processing all the elements, if the stack is empty, then the expression is balanced; otherwise, it is not.
bool checkValidParentheses(string& exp, int n)
{
if (n % 2 != 0)
return false;
stack<char> s;
for (int i = 0; i < n; i = i + 1)
{
if (exp[i] == '(' || exp[i] == '{' || exp[i] == '[')
s.push(exp[i]);
else if (exp[i] == ')' || exp[i] == '}' || exp[i] == ']')
{
if (s.empty())
return false;
char top = s.top();
s.pop();
if ((top == '(' && exp[i] != ')') ||
(top == '{' && exp[i] != '}') ||
(top == '[' && exp[i] != ']'))
return false;
}
}
return s.empty();
}
bool checkValidParentheses(string& exp)
{
stack<char> s;
char temp;
for (char ch : exp)
{
if (ch == '(' || ch == '[' || ch == '{')
{
s.push(ch);
continue;
}
if (s.empty())
return false;
temp = s.top();
s.pop();
switch (ch)
{
case ')':
if (temp == '{' || temp == '[')
return false;
break;
case '}':
if (temp == '(' || temp == '[')
return false;
break;
case ']':
if (temp == '(' || temp == '{')
return false;
break;
}
}
return s.empty();
}
We are running a single loop and performing constant operations at each iteration. So the time complexity is n * O(1) = O(n). From another perspective, we will be inserting and removing each opening parenthesis once from the stack in the worst case. This situation occurs when the expression is completely balanced. So, the total number of stack operations is n.
We are using extra space for the stack. The size of the stack will be O(n) in the worst case, so the space complexity is O(n).
In this approach, for each character exp[i], we check if it is an opening parenthesis. If it is, we push the corresponding closing parenthesis onto the stack. For example, if exp[i] is "(", then we push ")" onto the stack. This helps us keep track of the expected closing parentheses.
If exp[i] is not an opening parenthesis, then it must be a closing parenthesis. We check if the stack is not empty and if the top element of the stack is exp[i]. If they match, it means the current closing parenthesis matches the expected closing parenthesis. In such cases, we remove the top element from the stack.
If any of the above conditions is not satisfied, it means the expression is unbalanced. So, we return false.
bool checkValidParentheses(string& exp)
{
int n = exp.length();
if (n % 2 != 0)
return false;
stack<char> s;
for (int i = 0; i < n; i = i + 1)
{
if (exp[i] == '(')
s.push(')');
else if (exp[i] == '{')
s.push('}');
else if (exp[i] == '[')
s.push(']');
else if (!s.empty() && s.top() == exp[i])
s.pop();
else
return false;
}
return s.empty();
}
We are running a single loop n times and performing constant operations at each iteration. So, the time complexity is n * O(1) = O(n).
The worst case occurs when the expression is completely balanced, and we will traverse the entire string. In this situation, we insert and remove each closing parenthesis only once. So, the total number of stack operations in the worst case = The total number of closing parentheses in a balanced expression = n/2.
We are using extra space for the stack. So, the space complexity is O(n).
This approach is similar to the stack approach, but for validating the balance of parentheses in the expression, we scan the expression from left to right and use the starting indexes of the same input array as a stack to store the opening parentheses. During this process, we also maintain a count variable to keep track of the number of opening parentheses encountered.
The idea is simple: A balanced expression should have an equal number of opening and closing parentheses, and they should be properly nested and matched. So, the expression is balanced if and only if the count becomes -1 at the end of the loop.
Step 1: We initialize a count variable to track the count of opening parentheses. Now we iterate from 0 to n-1 using a loop.
Step 2: If the current character exp[i] is an opening parenthesis.
We increment the count and store the opening parenthesis in the count-th position of the exp string. This is similar to pushing the opening parenthesis onto the stack.
Step 3: If the current character is a closing parenthesis.
If the count is -1, it means there is no corresponding opening parenthesis for the current closing parenthesis. So the expression is unbalanced and we return false.
If the count is not -1, we retrieve the opening parenthesis from the top of the stack (stored at exp[count]) and compare it with the current closing parenthesis exp[i].
Step 4: After the loop, we check if the count is -1. If it is, then all opening parentheses have been matched and popped from the stack. So the expression is balanced and we return true. Otherwise, there are unmatched opening parentheses remaining. So the expression is unbalanced, and we return false.
bool checkValidParentheses(string& exp)
{
int n = exp.length();
int count = -1;
for (int i = 0; i < n; i = i + 1)
{
if (exp[i] == '(' || exp[i] == '{' || exp[i] == '[')
{
count = count + 1;
exp[count] = exp[i];
}
else if (exp[i] == ')' || exp[i] == '}' || exp[i] == ']')
{
if (count == -1)
return false;
char openingParenthesis = exp[count];
if ((openingParenthesis == '(' && exp[i] != ')') ||
(openingParenthesis == '{' && exp[i] != '}') ||
(openingParenthesis == '[' && exp[i] != ']'))
{
return false;
}
count = count - 1;
}
}
return (count == -1);
}
Note: Strings in Python are immutable i.e. we cannot change individual characters of a string directly. If we try to modify a string in place, it will throw an error in Python. In other words, this assignment operation exp[count] = exp[i] attempts to assign a new value to a character in the exp string. This is not allowed in Python. To fix this issue, we can create a new string or list to store the modified expression.
We are running a single loop n times and performing constant operations at each iteration. So the time complexity is n * O(1) = O(n). We are modifying the same input array as a stack to store opening parentheses. So the space complexity is O(1).
The simple idea is to iterate over the string of parentheses and keep track of the count of opening parentheses encountered. For each closing parenthesis, we decrement the count to match it with the corresponding opening parenthesis. If the count becomes negative at any point or if there are unmatched opening parentheses remaining at the end, the expression is unbalanced. Otherwise, the expression is balanced.
We initialize a boolean variable balanceFlag as true to keep track of the balanced status of the expression. We also initialize a variable count to keep track of the number of opening parentheses encountered.
bool checkValidParentheses(string& exp, int n)
{
bool balanceFlag = true;
int count = 0;
for (int i = 0; i < n; i = i + 1)
{
if (exp[i] == '(')
count = count + 1;
else
count = count - 1;
if (count < 0)
{
balanceFlag = false;
break;
}
}
if (count != 0)
balanceFlag = false;
return balanceFlag;
}
If you have any queries or feedback, please write us at contact@enjoyalgorithms.com. Enjoy learning, Enjoy algorithms!