4.9 KiB
The Parentheses Balancing Problem (RIP Exercise)
What is this exercise about?
Imagine you have a string of parentheses like this: "(()".
Think of parentheses like doors in a building:
(is like opening a door)is like closing a door
For everything to work properly, every door you open must have a matching door that closes it!
The Problem
Sometimes we get strings where the doors don't match properly. For example:
"((("- We opened 3 doors but never closed any!"())"- We opened 1 door, closed 1 door, but then tried to close another door that was never opened!
Our job is to fix these strings by removing the minimum number of parentheses (but replacing them with spaces instead of deleting them completely).
Real-World Example
Let's say you have: "(()"
This means:
- Open door 1:
( - Open door 2:
( - Close door 2:
) - But door 1 is still open! 😱
To fix this, we need to either:
- Remove one of the opening doors:
()(remove first() - Or remove one of the opening doors:
( )(remove second()
Both solutions work!
How Our Program Works
Step 1: Count the Problems
// This function counts how many parentheses we need to remove
void calculate_removals(char *str, int *left_rem, int *right_rem)
{
int left = 0; // Count of unmatched opening parentheses
int right = 0; // Count of unmatched closing parentheses
// Go through each character
while (str[i])
{
if (str[i] == '(')
left++; // Found an opening door
else if (str[i] == ')')
{
if (left > 0)
left--; // Found a closing door for an open one
else
right++; // Found a closing door with no matching open door
}
}
}
Example with "(()":
- Start:
left = 0,right = 0 - See
(:left = 1(one unmatched opening) - See
(:left = 2(two unmatched openings) - See
):left = 1(one opening got matched) - End:
left = 1,right = 0
So we need to remove 1 opening parenthesis.
Step 2: Try All Possible Solutions
Think of it like trying different combinations:
// This function tries removing different parentheses to find all valid solutions
void solve(char *s, int pos, int left_rem, int right_rem, int open, char *path)
{
// If we've looked at all characters
if (pos == len)
{
// Check if we removed exactly what we needed and everything balances
if (left_rem == 0 && right_rem == 0 && open == 0)
add_result(results, path); // This is a valid solution!
return;
}
// Try removing this parenthesis (replace with space)
if (s[pos] == '(' && left_rem > 0)
{
path[pos] = ' '; // Replace with space
solve(s, pos + 1, left_rem - 1, right_rem, open, path);
}
// Try keeping this parenthesis
path[pos] = s[pos];
if (s[pos] == '(')
solve(s, pos + 1, left_rem, right_rem, open + 1, path);
// ... and so on
}
Step 3: Avoid Duplicates
We use a list to store all unique solutions:
// This makes sure we don't print the same solution twice
void add_result(t_result **results, char *str)
{
// Check if we already have this solution
current = *results;
while (current)
{
if (ft_strcmp(current->str, str) == 0)
return; // Already have it, don't add again
current = current->next;
}
// It's new, so add it to our list
new->str = ft_strdup(str);
new->next = *results;
*results = new;
}
Example Walkthrough
Let's trace through "(()" step by step:
Initial Analysis:
- Need to remove 1 opening parenthesis (
left_rem = 1) - Need to remove 0 closing parentheses (
right_rem = 0)
Trying Different Positions:
Position 0 (first ():
- Try removing it:
" ()"- Check: removed 1 opening ✓, no unmatched doors ✓
- Valid solution! ✅
Position 1 (second ():
- Try removing it:
"( )"- Check: removed 1 opening ✓, no unmatched doors ✓
- Valid solution! ✅
Position 2 (the )):
- Can't remove it (we need to remove openings, not closings)
Final Output:
()
( )
More Complex Example: "()())()"
This string has:
- 3 opening doors:
(,(,( - 4 closing doors:
),),),)
So we have 1 extra closing door that needs to be removed.
All possible solutions:
- Remove closing at position 2:
"()( )()" - Remove closing at position 3:
"()() ()" - Remove closing at position 4:
"( ())()"
Why This Exercise is Useful
This problem teaches us:
- Problem-solving: Break down complex problems into smaller steps
- Recursion: Try all possibilities systematically
- Data structures: Use lists to store and manage results
- Optimization: Find the minimum changes needed
It's like being a door inspector - you need to make sure every building (string) has properly matched doors (parentheses) with the minimum number of changes!