[LeetCode解題攻略] 40. Combination Sum II

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

題目描述

給定一個可能包含重複數字的整數數組 candidates 和一個目標值 target,找出所有的唯一組合,使得這些組合中的數字和為 target

數組中的每個數字只能在每個組合中使用一次


範例 1

輸入: candidates = [10,1,2,7,6,1,5], target = 8
輸出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

範例 2

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

條件限制

  • 所有的數字都是正整數。
  • 答案中的每個組合都是唯一的。
  • 答案中的組合可以按任意順序返回。

解題思路

這是一個典型的回溯法(Backtracking)問題,但與 39. Combination Sum 不同的是,這裡的數組中可能包含重複元素,我們需要特別處理去重問題。

核心點:

  1. 數組中可能有重複元素,我們需要避免出現重複的組合。
  2. 將數組排序後,對於相同元素,只允許第一次進入回溯,後續跳過。
  3. 每個數字只能使用一次,這與 39. Combination Sum 中數字可重複選取的要求不同。

解法一:回溯法

思路

  1. 排序:對數組進行排序,有助於處理重複元素的問題。
  2. 剪枝:在遞迴中,當 target 小於 0 時,停止遞迴。
  3. 跳過重複元素:在同一層遞迴中,如果數字和前一個數字相同,則跳過,避免重複組合。

程式碼

class Solution:
def combinationSum2(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)):
# 跳過同層中重複的數字
if i > start and candidates[i] == candidates[i - 1]:
continue

path.append(candidates[i]) # 選擇當前數字
backtrack(i + 1, target - candidates[i], path) # 遞迴進入下一層
path.pop() # 撤銷選擇

candidates.sort() # 排序
result = []
backtrack(0, target, [])
return result

時間與空間複雜度分析

  • 時間複雜度:O(2^n),n 為候選數組的長度。最壞情況下,我們需要探索所有可能的組合。
  • 空間複雜度:O(n),n 是遞迴深度(對應目標值 target)。

解法二:動態規劃

雖然回溯法已經是該問題的主流解法,但我們可以嘗試用動態規劃解決。


思路

  1. 排序:與回溯法類似,排序能幫助處理重複數字的問題。
  2. 狀態定義
    • 使用 dp[i] 表示所有和為 i 的組合。
  3. 轉移方程
    • 當考慮某個數字 num 時,對於所有和 j,將 dp[j - num] 的組合加上 num,形成新的組合,加入 dp[j]。
  4. 去重
    • 過程中需檢查是否有重複的組合。

程式碼

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

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

return [list(comb) for comb in dp[target]]

時間與空間複雜度分析

  • 時間複雜度:O(n * target),其中 n 是候選數組的長度,target 是目標值。
  • 空間複雜度:O(target),需要儲存 dp 陣列。

結論

  1. 回溯法 是解決該問題的經典方法,適合大多數情況。
  2. 動態規劃 雖然可以處理該問題,但實際使用中較少,適合性能要求較高的場合。
  3. 若候選數組較小,建議使用回溯法;若目標值較大,可以考慮動態規劃。
歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
給定一個無重複正整數數組 candidates 和一個目標值 target,找出所有可以使數字和為 target 的組合。 數組中的數字可以無限制重複選取,並且所有的組合需要是唯一的。
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]。
給定一個無重複正整數數組 candidates 和一個目標值 target,找出所有可以使數字和為 target 的組合。 數組中的數字可以無限制重複選取,並且所有的組合需要是唯一的。
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]。
你可能也想看
Google News 追蹤
Thumbnail
題目敘述 Combination Sum II_Leetcode #40 給定一個整數陣列candidates 和 目標值target。 每個陣列元素只能選擇一次,請問有多少種組合方法,可以使得組合數總和 = target? 請把滿足組合數總和 = target的組合方法以陣列的形式返回答案
Thumbnail
題目敘述 Combination Sum IV 給定一個輸入陣列nums,和目標值target,從nums裡面挑數字去湊出總和 = target,數字可以重複挑選。 請問有多少排列數可以湊出target? 註: 排列數的意思就是位置不同代表兩種不同的方法數。
Thumbnail
題目敘述 Single Number II 給定一個輸入陣列,已知有一個烙單的數字,其他剩餘的數字都恰巧出現三次。 請找出這個烙單的數字。 題目額外提出限制,請使用O(n)線性時間、O(1)常數空間複雜度的演算法。 測試範例 Example 1: Input: nums = [2,2,
Thumbnail
題目敘述 Single Number III 給定一個輸入陣列,已知有兩個烙單的數字,其他剩餘的數字都恰巧出現兩次。 請找出這兩個烙單的數字。 題目額外提出限制,請使用O(n)線性時間、O(1)常數空間複雜度的演算法。 測試範例 Example 1: Input: nums = [1,
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
題目敘述 題目會給定一個整數陣列arr,要求我們判斷是否每個元素的出現次數都不同? 題目的原文敘述 測試範例 Example 1: Input: arr = [1,2,2,1,1,3] Output: true Explanation: The value 1 has 3 occurre
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 II 給定一個輸入陣列,已知有一個烙單的數字,其他剩餘的數字都恰巧出現三次。 請找出這個烙單的數字。 題目額外提出限制,請使用O(n)線性時間、O(1)常數空間複雜度的演算法。 測試範例 Example 1: Input: nums = [2,2,
Thumbnail
題目敘述 Single Number III 給定一個輸入陣列,已知有兩個烙單的數字,其他剩餘的數字都恰巧出現兩次。 請找出這兩個烙單的數字。 題目額外提出限制,請使用O(n)線性時間、O(1)常數空間複雜度的演算法。 測試範例 Example 1: Input: nums = [1,
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
題目敘述 題目會給定一個整數陣列arr,要求我們判斷是否每個元素的出現次數都不同? 題目的原文敘述 測試範例 Example 1: Input: arr = [1,2,2,1,1,3] Output: true Explanation: The value 1 has 3 occurre
Thumbnail
題目敘述 題目會給我們一個整數陣列,裡面包含各種正整數,每回合可以消去兩個相同的數字,或者消去三個相同的數字。問最少需要幾次消去,才能讓陣列為空? 如果無解,則返回-1 詳細的題目可在這裡看到 測試範例 Example 1: Input: nums = [2,3,3,2,2,4,2,3,