179 lines
4.9 KiB
Markdown
179 lines
4.9 KiB
Markdown
# 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:
|
|
1. Open door 1: `(`
|
|
2. Open door 2: `(`
|
|
3. Close door 2: `)`
|
|
4. 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
|
|
|
|
```c
|
|
// 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:
|
|
|
|
```c
|
|
// 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:
|
|
|
|
```c
|
|
// 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:
|
|
1. **Problem-solving**: Break down complex problems into smaller steps
|
|
2. **Recursion**: Try all possibilities systematically
|
|
3. **Data structures**: Use lists to store and manage results
|
|
4. **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! |