↓快轉到主要內容
  1. LeetCode/

LeetCode 40: Combination Sum II

·1 分鐘· ·
LeetCode Medium Array Backtracking
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: medium 第一次嘗試:2022-10-21

  • 提交紀錄:Wrong Answer ×2 → Runtime Error → Time Limit Exceeded ×2 → Runtime Error ×2 → Accepted → Runtime Error ×2 → Accepted → Wrong Answer ×3 → Runtime Error → Accepted → Wrong Answer ×3 → Accepted

解題思路
#

跟 LC 39 差兩個地方(Backtracking 變化四):

  1. 每個數只能用一次:下一層從 i + 1 開始。
  2. candidates 有重複:排序後,同一層如果 candidates[i] == candidates[i - 1](而且 i > start)就跳過。同一層選相同的值會產生一模一樣的子樹。

注意是同一層跳過,不同層選相同的值是允許的,例如 [1, 1, 6]。

我的嘗試
#

這題提交了 20 次,分三個階段:

  • 2022-10-21:第一版下一層從 i 開始,同一個數被重複使用:[1]、target = 6 回傳 [[1, 1, 1, 1, 1, 1]];改成 i + 1 之後沒有去重,[3, 3, 5]、target = 8 回傳兩次 [3, 5];接著用 not in self.res 去重,TLE 了兩次。
  • 2022-10-30 重寫,同樣沒有去重的問題又出現了三次。
  • 2022-11-23:一版先檢查「candidates 是空的就回傳」,最後一個數剛好湊滿時還沒記錄就回傳了:[1]、target = 1 回傳空的。最後加上「同一層跳過相同的值」才 AC。

正確解法
#

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()
        res = []
        def dfs(start, remain, path):
            if remain == 0:
                res.append(path[:])
                return
            for i in range(start, len(candidates)):
                if i > start and candidates[i] == candidates[i - 1]:
                    continue
                if candidates[i] > remain:
                    break
                path.append(candidates[i])
                dfs(i + 1, remain - candidates[i], path)
                path.pop()
        dfs(0, target, [])
        return res

複雜度
#

時間 O(2^n),空間 O(n)。

要特別避免的錯誤
#

  • 下一層從 i + 1 開始,每個數只用一次。
  • 去重要在同一層做(i > start),而且要先排序。
  • 用 not in res 去重會 TLE。
  • 先判斷 remain == 0 再判斷「沒有數可以選」,不然最後一個數剛好湊滿時會漏掉。

面試口說整理
#

每個數只能用一次而且陣列有重複,所以我先排序,回溯時下一層從 i + 1 開始,同一層遇到跟前一個相同的值就跳過,避免產生一樣的組合;超過剩下的目標就停止。

相關文章

LeetCode 39: Combination Sum
·1 分鐘
LeetCode Medium Array Backtracking
LeetCode 39 解題筆記:同一個數可以重複選,所以遞迴時下一層從 i 開始(不是 i + 1),這樣也避免了順序不同的重複
LeetCode 46: Permutations
·1 分鐘
LeetCode Medium Array Backtracking
LeetCode 46 解題筆記:每一層從還沒用過的數裡選一個,用 used 陣列標記,path 滿了就記錄
LeetCode 31: Next Permutation
·1 分鐘
LeetCode Medium Array Two-Pointers
LeetCode 31 解題筆記:從右邊找第一個下降的位置 i,跟右邊比它大的最小值交換,再把 i 之後反轉;比較時要包含等於
LeetCode 33: Search in Rotated Sorted Array
·1 分鐘
LeetCode Medium Array Binary-Search
LeetCode 33 解題筆記:旋轉後 mid 的左右一定有一邊是排序好的,判斷目標在不在那一邊,在就往那邊找,不在就去另一邊
LeetCode 34: Find First and Last Position of Element in Sorted Array
·1 分鐘
LeetCode Medium Array Binary-Search
LeetCode 34 解題筆記:做兩次 lower bound:第一個 >= target 的位置,以及第一個 >= target + 1 的位置減一
LeetCode 36: Valid Sudoku
·1 分鐘
LeetCode Medium Array Hash-Table Matrix
LeetCode 36 解題筆記:每個數字在列、欄、3 × 3 宮格各只能出現一次;用 (數字, 列)、(數字, 欄)、(數字, 宮格) 當 key 放進同一個集合