leetcode
leetcode 1 ~ 50
括号生成

括号生成

难度:

标签:

题目描述

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

 

示例 1:

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

示例 2:

输入:n = 1
输出:["()"]

 

提示:

  • 1 <= n <= 8

代码结果

运行时间: 52 ms, 内存: 15.1 MB


/*
 * This solution utilizes a stream-based approach to generate valid parentheses.
 * We still use backtracking internally but convert the list to a stream at the end.
 */
 
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
 
public class GenerateParenthesesStream {
    public List<String> generateParenthesis(int n) {
        List<String> result = new ArrayList<>();
        backtrack(result, "", 0, 0, n);
        return result.stream().collect(Collectors.toList());
    }
 
    private void backtrack(List<String> result, String current, int open, int close, int max) {
        if (current.length() == max * 2) {
            result.add(current);
            return;
        }
 
        if (open < max) {
            backtrack(result, current + "(", open + 1, close, max);
        }
        if (close < open) {
            backtrack(result, current + ")", open, close + 1, max);
        }
    }
}
 

解释

方法:

该题解使用回溯法生成有效的括号组合。通过递归的方式,不断地尝试添加左括号和右括号,同时使用一个栈来记录当前未匹配的左括号数量。在递归过程中,根据栈的大小和已生成的括号数量,选择添加左括号或右括号。当生成的括号数量达到 2*n,且栈为空时,说明生成了一个有效的括号组合,将其加入结果列表中。

时间复杂度:

O((4^n) / (n^(1/2)))

空间复杂度:

O((4^n) / (n^(1/2)))

代码细节讲解

🦆
为什么在选择括号类型时,栈的大小会直接决定可以添加的括号类型?
在生成有效括号的过程中,栈用来记录未匹配的左括号。如果栈为空,意味着没有未匹配的左括号,因此只能添加左括号。如果栈的大小已达到n,表示左括号已经用完,此时只能添加右括号以匹配已存在的左括号。栈的大小实际上反映了当前左括号和右括号的添加状态,决定了下一步可以安全添加的括号类型,以保证括号序列的有效性。
🦆
题解中提到的`卡特兰数公式`如何应用于有效括号的数量计算?能否解释其数学依据?
卡特兰数是一种重要的组合数学公式,用于解决各种在结构和数量上受限的组合问题。有效括号的问题可以用卡特兰数计算,因为每个有效的括号组合必须满足左括号数量等于右括号数量,并且在任意前缀中左括号数量不少于右括号数量。第n个卡特兰数是:C(n) = 1/(n+1) * (2n choose n),它准确地计算了n对括号能形成的有效组合数量。
🦆
递归函数`backtrack`在进行回溯时,为何需要对括号添加和移除操作同时进行栈的出栈和入栈操作?
递归函数`backtrack`通过试探性地添加左括号或右括号并递归,检查生成的括号组合是否有效。在每次递归调用后,需要撤销之前的操作(添加的括号),确保每个可能的括号位置都可以正确尝试所有的选项。对于栈操作,添加左括号时入栈,撤销时相应地出栈,以保持栈状态正确反映未匹配的左括号数量,这是确保生成所有有效组合的关键步骤。
🦆
在递归生成括号的过程中,`if len(path) >= 2 * n`的检查是为了什么?是否和括号生成完成有关?
该检查确保当生成的括号数量达到最大(即2*n个,n对左括号和n对右括号)时停止添加新括号,这是因为进一步的添加会导致括号数量超过要求,破坏括号组合的有效性。当`len(path) == 2 * n`且栈为空时,表示已生成一个完整的有效括号组合。
🦆
题解中提到的时间复杂度和空间复杂度计算,是否可以通过具体的例子详细说明其如何被计算?
考虑n=3的情况,生成的有效括号组合数(卡特兰数)是5。每个组合的生成涉及到6个字符的添加过程。时间复杂度主要由生成各个组合的过程决定,即C(3)次完整的递归流程,每个流程中的操作次数与n成线性关系,因此时间复杂度为O((4^n) / (n^(1/2)))。空间复杂度包括递归调用栈空间和结果存储空间,对于每个递归调用,栈的最大深度为2n,而存储所有结果的空间取决于组合数和每个组合的长度,故空间复杂度为O(C(n) * n),即O((4^n) / (n^(1/2)))。
🦆
在处理递归的过程中,为什么要单独处理栈大小为0或超过n的情况,这与有效括号生成的逻辑有何关系?
栈大小为0表示没有未匹配的左括号,因此只能添加左括号。栈大小超过n时,意味着左括号的数量已达到最大值n,此时必须添加右括号来匹配已有的左括号。这种处理确保每一步操作都符合有效括号序列的要求,即在任何时刻,添加右括号的数量不能超过左括号的数量。

相关问题

电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

 

示例 1:

输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

示例 2:

输入:digits = ""
输出:[]

示例 3:

输入:digits = "2"
输出:["a","b","c"]

 

提示:

  • 0 <= digits.length <= 4
  • digits[i] 是范围 ['2', '9'] 的一个数字。

有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

 

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:

输入:s = "(]"
输出:false

 

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成