[LeetCode 解題攻略] 39. Combination Sum

更新於 發佈於 閱讀時間約 6 分鐘

題目描述

給定一個無重複正整數數組 candidates 和一個目標值 target,找出所有可以使數字和為 target 的組合。

數組中的數字可以無限制重複選取,並且所有的組合需要是唯一的。


範例 1

輸入: candidates = [2,3,6,7], target = 7
輸出: [[2,2,3],[7]]
解釋:
2 + 2 + 3 = 7
7 = 7

範例 2

輸入: candidates = [2,3,5], target = 8
輸出: [[2,2,2,2],[2,3,3],[3,5]]

範例 3

輸入: candidates = [2], target = 1
輸出: []

條件限制

  • 所有數字(包括 target)均為正整數。
  • 數組中所有數字互不相同。
  • 答案中的組合可以按任意順序返回。

解題思路

這是一個經典的「組合問題」,解題的核心是利用回溯法(Backtracking)

回溯法的思路

  1. 將候選數組進行排序(有助於提前剪枝)。
  2. 使用遞迴探索所有可能的組合。
  3. 當當前組合的總和等於目標時,將組合加入答案。
  4. 如果總和超過目標值,則停止探索(剪枝)。

解法一:回溯法

思路

  1. 從候選數組中依次選取元素。
  2. 選取後,繼續探索包含該元素的子問題。
  3. 如果總和超過 target,停止探索(剪枝)。
  4. 當總和等於 target,將當前組合加入結果集。

程式碼

class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
def backtrack(start, target, path):
if target == 0:
result.append(list(path)) # 找到一個組合
return
if target < 0:
return # 剪枝

for i in range(start, len(candidates)):
path.append(candidates[i]) # 選擇當前元素
backtrack(i, target - candidates[i], path) # 繼續探索
path.pop() # 撤銷選擇

result = []
candidates.sort() # 排序有助於剪枝
backtrack(0, target, [])
return result

時間與空間複雜度分析

  • 時間複雜度:O(2^t),t 是目標值 target,因為每個數字可能被多次選取並組成不同的組合。
  • 空間複雜度:O(t),遞迴的最大深度為 target

解法二:動態規劃

思路

  1. 將問題轉化為背包問題(完全背包)。
  2. 定義 dp[i] 為目標和為 i 的所有組合。
  3. 對於每個數字 num 和目標值 j,若 j >= num,則將 dp[j - num] 中的組合加上 num,形成新的組合,並存入 dp[j]

程式碼

class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
dp = [[] for _ in range(target + 1)]
dp[0] = [[]] # 和為 0 時的組合為空組合

for num in candidates:
for j in range(num, target + 1):
for comb in dp[j - num]:
dp[j].append(comb + [num])

return dp[target]

時間與空間複雜度分析

  • 時間複雜度:O(n * target),其中 n 是候選數組的大小,target 是目標值。
  • 空間複雜度:O(target),因為需要儲存每個和的組合。

結論

  1. 回溯法 是解決這類組合問題的直觀方法,適合初學者。
  2. 動態規劃 適合對性能要求較高的情況,但編碼複雜度較高。
  3. 根據具體問題的規模選擇合適的解法:當 candidates 較小時,使用回溯法;當目標值較大時,考慮動態規劃。
歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Count-and-say序列是透過遞歸公式定義的數字串序列: countAndSay(1) = "1" countAndSay(n) 是 countAndSay(n - 1) 的Run-length encoding。
編寫一個程式,求解數獨(Sudoku)問題。
給定一個 9x9 的數獨棋盤,請驗證這個棋盤是否有效。
給定一個升序排序的整數數組 nums 和一個目標值 target,請找出目標值應插入的位置,保證插入後數組仍然是有序的。 必須設計一個演算法,其時間複雜度為 O(log n)。
給定一個按升序排序的整數數組 nums 和一個目標值 target,請在數組中找到目標值的 第一個 和 最後一個 位置,並以一個長度為 2 的列表返回結果。如果數組中不存在目標值,返回 [-1, -1]。
給定一個按照升序排序的整數數組,但該數組可能在某個未知的軸點旋轉(例如,nums = [4,5,6,7,0,1,2])。請你在數組中搜索目標值 target,如果找到則返回其索引,否則返回 -1。
Count-and-say序列是透過遞歸公式定義的數字串序列: countAndSay(1) = "1" countAndSay(n) 是 countAndSay(n - 1) 的Run-length encoding。
編寫一個程式,求解數獨(Sudoku)問題。
給定一個 9x9 的數獨棋盤,請驗證這個棋盤是否有效。
給定一個升序排序的整數數組 nums 和一個目標值 target,請找出目標值應插入的位置,保證插入後數組仍然是有序的。 必須設計一個演算法,其時間複雜度為 O(log n)。
給定一個按升序排序的整數數組 nums 和一個目標值 target,請在數組中找到目標值的 第一個 和 最後一個 位置,並以一個長度為 2 的列表返回結果。如果數組中不存在目標值,返回 [-1, -1]。
給定一個按照升序排序的整數數組,但該數組可能在某個未知的軸點旋轉(例如,nums = [4,5,6,7,0,1,2])。請你在數組中搜索目標值 target,如果找到則返回其索引,否則返回 -1。
你可能也想看
Google News 追蹤
提問的內容越是清晰,強者、聰明人越能在短時間內做判斷、給出精準的建議,他們會對你產生「好印象」,認定你是「積極」的人,有機會、好人脈會不自覺地想引薦給你
Thumbnail
題目敘述 Combination Sum II_Leetcode #40 給定一個整數陣列candidates 和 目標值target。 每個陣列元素只能選擇一次,請問有多少種組合方法,可以使得組合數總和 = target? 請把滿足組合數總和 = target的組合方法以陣列的形式返回答案
Thumbnail
題目敘述 Combination Sum IV 給定一個輸入陣列nums,和目標值target,從nums裡面挑數字去湊出總和 = target,數字可以重複挑選。 請問有多少排列數可以湊出target? 註: 排列數的意思就是位置不同代表兩種不同的方法數。
Thumbnail
題目敘述 Single Number III 給定一個輸入陣列,已知有兩個烙單的數字,其他剩餘的數字都恰巧出現兩次。 請找出這兩個烙單的數字。 題目額外提出限制,請使用O(n)線性時間、O(1)常數空間複雜度的演算法。 測試範例 Example 1: Input: nums = [1,
Thumbnail
Leetcode 精選75題 題目與題解 熱門考點 目錄 (持續更新中) 建議從左側目錄 或者 按Ctrl+F輸入關鍵字進行搜尋
Thumbnail
子集合生成是一道經典的組合類上機考和面試題目。本篇文章介紹多個不同的解決方案,以及相關演算法框架。主要目標是給定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,我們每回合可以挑選總和為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
題目敘述 題目會給我們一個整數陣列,裡面包含各種正整數,每回合可以消去兩個相同的數字,或者消去三個相同的數字。問最少需要幾次消去,才能讓陣列為空? 如果無解,則返回-1 詳細的題目可在這裡看到 測試範例 Example 1: Input: nums = [2,3,3,2,2,4,2,3,
提問的內容越是清晰,強者、聰明人越能在短時間內做判斷、給出精準的建議,他們會對你產生「好印象」,認定你是「積極」的人,有機會、好人脈會不自覺地想引薦給你
Thumbnail
題目敘述 Combination Sum II_Leetcode #40 給定一個整數陣列candidates 和 目標值target。 每個陣列元素只能選擇一次,請問有多少種組合方法,可以使得組合數總和 = target? 請把滿足組合數總和 = target的組合方法以陣列的形式返回答案
Thumbnail
題目敘述 Combination Sum IV 給定一個輸入陣列nums,和目標值target,從nums裡面挑數字去湊出總和 = target,數字可以重複挑選。 請問有多少排列數可以湊出target? 註: 排列數的意思就是位置不同代表兩種不同的方法數。
Thumbnail
題目敘述 Single Number III 給定一個輸入陣列,已知有兩個烙單的數字,其他剩餘的數字都恰巧出現兩次。 請找出這兩個烙單的數字。 題目額外提出限制,請使用O(n)線性時間、O(1)常數空間複雜度的演算法。 測試範例 Example 1: Input: nums = [1,
Thumbnail
Leetcode 精選75題 題目與題解 熱門考點 目錄 (持續更新中) 建議從左側目錄 或者 按Ctrl+F輸入關鍵字進行搜尋
Thumbnail
子集合生成是一道經典的組合類上機考和面試題目。本篇文章介紹多個不同的解決方案,以及相關演算法框架。主要目標是給定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,我們每回合可以挑選總和為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
題目敘述 題目會給我們一個整數陣列,裡面包含各種正整數,每回合可以消去兩個相同的數字,或者消去三個相同的數字。問最少需要幾次消去,才能讓陣列為空? 如果無解,則返回-1 詳細的題目可在這裡看到 測試範例 Example 1: Input: nums = [2,3,3,2,2,4,2,3,