1 minute read

Today, I took on a more challenging problem within the realm of backtracking.

Problem Description:

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.

Example 1:

Input: n = 3
Output: ["((()))","(()())","(())()","()(())","()()()"]

Example 2:

Input: n = 1
Output: ["()"]

My Explanation:

In this algorithm, I’m generating valid combinations of parentheses for a given number, n. I use backtracking to explore all possible combinations. The recursive function backtrack takes parameters: i to track the position in the combination, open to count the open parentheses, n for the target number, result to store valid combinations, and curr for the current combination being formed.

The base cases ensure that the number of open parentheses is within bounds.

If i reaches twice n, it checks if the combination is valid, and if so, adds it to the result.

In each step, I iterate through possible parentheses ( and ) and explore the combinations by adjusting the count of open parentheses accordingly. The final result contains all valid combinations of parentheses for the given n.

Python Solution:

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        def backtrack(i, open, n, result, curr):
            if open > n or open < 0:
                return
            
            if i == n * 2:
                if open == 0:
                    result.append(''.join(curr))
                return

            for c in '()':
                if c == '(':
                    backtrack(i + 1, open + 1,  n, result, curr + [c])
                else:
                    backtrack(i + 1, open - 1, n, result, curr + [c])

        result = []
        backtrack(0, 0, n, result, [])
        return result

ChatGPT version for improving my algorithm

Pruning Unnecessary Paths:

Instead of iterating through both ‘(‘ and ‘)’ in every step, you can prioritize the ‘(‘ when open < n and ‘)’ when open > 0. This helps in pruning unnecessary paths early in the recursion.

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        def backtrack(i, open_count, n, result, current):
            if open_count > n or open_count < 0:
                return

            if i == n * 2:
                if open_count == 0:
                    result.append(''.join(current))
                return

            for c in '()':
                if c == '(' and open_count < n:
                    backtrack(i + 1, open_count + 1, n, result, current + [c])
                elif c == ')' and open_count > 0:
                    backtrack(i + 1, open_count - 1, n, result, current + [c])

        result = []
        backtrack(0, 0, n, result, [])
        return result