EX_03/rip/README.md
2025-09-22 17:26:39 +01:00

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:

  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

// 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:

  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!