[LeetCode解題攻略] 22. Generate Parentheses

更新 發佈閱讀 8 分鐘

題目描述

給定一個整數 n,請生成所有可能由 n 對括號組成的 有效括號組合


範例 1:

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

範例 2:
Input: n = 1
Output: ["()"]


解題思路

本題是經典的回溯問題,主要挑戰在於:

  1. 正確地生成所有組合。
  2. 確保生成的括號組合有效。

解法一:回溯法 (Backtracking)

思路

  1. 使用遞歸函數進行回溯:
    • 當前生成的括號序列存儲在變量 current 中。
    • open 表示目前已使用的左括號數量。
    • close 表示目前已使用的右括號數量。
  2. 遞歸條件:
    • 如果左括號的數量小於 n,則可以繼續添加左括號。
    • 如果右括號的數量小於左括號,則可以繼續添加右括號。
  3. 終止條件:
    • 當 current 長度等於 2 * n(即 n 對括號的總字符數),將 current 加入結果集。
  4. 使用回溯法逐步生成所有可能的組合,並通過條件檢查確保有效性。

程式碼實現 (Python)

class Solution:
def generateParenthesis(self, n: int) -> List[str]:
result = []

def backtrack(current: str, open: int, close: int):
# 終止條件
if len(current) == 2 * n:
result.append(current)
return

# 如果可以添加左括號
if open < n:
backtrack(current + "(", open + 1, close)

# 如果可以添加右括號
if close < open:
backtrack(current + ")", open, close + 1)

# 開始回溯
backtrack("", 0, 0)
return result

時間與空間複雜度

  • 時間複雜度:O(4^n / √n)
  • 空間複雜度:O(n)

解法二:動態規劃 (Dynamic Programming)

思路

  1. 使用動態規劃的思想構造結果。
  2. 定義 dp[i] 表示由 i 對括號組成的所有合法括號組合。
  3. 對於每個 i,合法的組合可以表示為:
    • 將 p 對括號組合包裹在一對括號中:("(" + dp[p] + ")" + dp[q]),其中 p + q = i - 1。
  4. 從小到大逐步計算所有組合。

程式碼實現 (Python)

class Solution:
def generateParenthesis(self, n: int) -> List[str]:
dp = [[] for _ in range(n + 1)]
dp[0] = [""] # 0 對括號時,只有空字串

for i in range(1, n + 1):
for p in range(i):
q = i - 1 - p
for left in dp[p]:
for right in dp[q]:
dp[i].append(f"({left}){right}")

return dp[n]

時間與空間複雜度

  • 時間複雜度:O(4^n / √n)
  • 空間複雜度:O(4^n / √n)

解法三:暴力生成 + 有效性檢查

思路

  1. 生成所有可能由 n 對括號組成的字符串組合(例如排列 2n 個括號的所有方式)。
  2. 檢查每個組合是否有效,將有效的加入結果集。
  3. 檢查括號有效性
    • 從左到右遍歷字符串,用變量 balance 表示當前的括號平衡值。
    • 遇到左括號 (balance + 1;遇到右括號 )balance - 1
    • 如果在遍歷過程中 balance < 0,則字符串無效。
    • 最終檢查 balance == 0,確保左右括號數量相等。

程式碼實現 (Python)

class Solution:
def generateParenthesis(self, n: int) -> List[str]:
from itertools import product

def is_valid(sequence: str) -> bool:
balance = 0
for char in sequence:
if char == "(":
balance += 1
else:
balance -= 1
if balance < 0:
return False
return balance == 0

# 生成所有可能的組合
all_combinations = product("()", repeat=2 * n)
result = ["".join(seq) for seq in all_combinations if is_valid(seq)]
return result

時間與空間複雜度

  • 時間複雜度:O(2^(2n) * n),生成所有排列需要 2^(2n),檢查有效性需要 O(n)。
  • 空間複雜度:O(2^(2n)),用於存儲所有可能的組合。

總結

本題是經典的括號生成問題,最常用的方法是 回溯法,它結構清晰且效率高,能夠在有限的遞歸深度內生成所有合法組合。動態規劃法則適合於理解更為結構化的解法,暴力法則可作為基礎練習。

留言
avatar-img
追極光的北極熊|軟體工程師的小天地
16會員
169內容數
歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
2025/04/04
給定一個非負整數陣列 nums,其中 nums[i] 代表你在索引 i 處最多可以向右跳幾步。 請判斷是否能夠從索引 0 跳到最後一個索引。
2025/04/04
給定一個非負整數陣列 nums,其中 nums[i] 代表你在索引 i 處最多可以向右跳幾步。 請判斷是否能夠從索引 0 跳到最後一個索引。
2025/03/28
給定一個 m x n 的矩陣 matrix,請按照 螺旋順序(spiral order) 返回矩陣中的所有元素。
2025/03/28
給定一個 m x n 的矩陣 matrix,請按照 螺旋順序(spiral order) 返回矩陣中的所有元素。
2025/03/20
這道題是 LeetCode 的經典題之一,要求我們找出 一個子陣列,使其和最大,並返回這個最大和的數值。
2025/03/20
這道題是 LeetCode 的經典題之一,要求我們找出 一個子陣列,使其和最大,並返回這個最大和的數值。
看更多
你可能也想看
Thumbnail
Leetcode #1945. Sum of Digits of String After Convert 給定一個由小寫字母組成的字串 s ,以及一個整數 k 。 首先,用英文字母順序的位置替換每個字母,將 s 轉換 為整數 並且計算digits sum,反覆迭代k次。
Thumbnail
Leetcode #1945. Sum of Digits of String After Convert 給定一個由小寫字母組成的字串 s ,以及一個整數 k 。 首先,用英文字母順序的位置替換每個字母,將 s 轉換 為整數 並且計算digits sum,反覆迭代k次。
Thumbnail
題目敘述 Combination Sum II_Leetcode #40 給定一個整數陣列candidates 和 目標值target。 每個陣列元素只能選擇一次,請問有多少種組合方法,可以使得組合數總和 = target? 請把滿足組合數總和 = target的組合方法以陣列的形式返回答案
Thumbnail
題目敘述 Combination Sum II_Leetcode #40 給定一個整數陣列candidates 和 目標值target。 每個陣列元素只能選擇一次,請問有多少種組合方法,可以使得組合數總和 = target? 請把滿足組合數總和 = target的組合方法以陣列的形式返回答案
Thumbnail
題目敘述 Combination Sum IV 給定一個輸入陣列nums,和目標值target,從nums裡面挑數字去湊出總和 = target,數字可以重複挑選。 請問有多少排列數可以湊出target? 註: 排列數的意思就是位置不同代表兩種不同的方法數。
Thumbnail
題目敘述 Combination Sum IV 給定一個輸入陣列nums,和目標值target,從nums裡面挑數字去湊出總和 = target,數字可以重複挑選。 請問有多少排列數可以湊出target? 註: 排列數的意思就是位置不同代表兩種不同的方法數。
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目敘述 題目會給定我們一個輸入陣列nums,要求我們掃描美個陣列元素nums[i],計算除了nums[i]以外的陣列元素連乘積。 題目的原文敘述 測試範例 Example 1: Input: nums = [1,2,3,4] Output: [24,12,8,6] nums[0] 以
Thumbnail
題目敘述 題目會給定我們一個輸入陣列nums,要求我們掃描美個陣列元素nums[i],計算除了nums[i]以外的陣列元素連乘積。 題目的原文敘述 測試範例 Example 1: Input: nums = [1,2,3,4] Output: [24,12,8,6] nums[0] 以
Thumbnail
題目敘述 題目會給定我們一個整數陣列nums,我們每回合可以挑選總和為K的兩個數字,形成一個K-Sum pair。 請問我們最多可以製造幾個K-Sum pair? 題目的原文敘述 測試範例 Example 1: Input: nums = [1,2,3,4], k = 5 Output
Thumbnail
題目敘述 題目會給定我們一個整數陣列nums,我們每回合可以挑選總和為K的兩個數字,形成一個K-Sum pair。 請問我們最多可以製造幾個K-Sum pair? 題目的原文敘述 測試範例 Example 1: Input: nums = [1,2,3,4], k = 5 Output
Thumbnail
題目敘述 題目會給我們一個參數k 和 目標值n。 請問我們從1~9內挑k個相異的數字,使得他們的總和為n 的組合數有多少? 挑選時,每個數字必須相異,而且每個數字只能選一次。 題目的原文敘述 測試範例 Example 1: Input: k = 3, n = 7 Output: [
Thumbnail
題目敘述 題目會給我們一個參數k 和 目標值n。 請問我們從1~9內挑k個相異的數字,使得他們的總和為n 的組合數有多少? 挑選時,每個數字必須相異,而且每個數字只能選一次。 題目的原文敘述 測試範例 Example 1: Input: k = 3, n = 7 Output: [
Thumbnail
題目敘述 題目會給我們一個輸入陣列nums,和一個指定的k值。 請問,在輸入陣列nums中,有幾個子陣列的元素總合恰好為k ? 例如: nums = [1,2,3], k = 3 則有兩個子陣列的元素總合為3,分別是[1,2] 和 [3] 如果是第一次聽到或接觸前綴和prefix的同學
Thumbnail
題目敘述 題目會給我們一個輸入陣列nums,和一個指定的k值。 請問,在輸入陣列nums中,有幾個子陣列的元素總合恰好為k ? 例如: nums = [1,2,3], k = 3 則有兩個子陣列的元素總合為3,分別是[1,2] 和 [3] 如果是第一次聽到或接觸前綴和prefix的同學
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News