# **Leetcode筆記(Combination Sum)**
:::info
:information_source: 題目 : Combination Sum, 類型 : dynamic programming , 等級 : medium
日期 : 2023/02/25,2023/04/22,2023/05/02,2023/07/10,2023/10/11,2023/12/02,2024/10/22,2025/03/04
:::
### 嘗試
```python
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
dp = [0] * (target + 1)
for i in range(target + 1):
for j in range(len(candidates)):
if i == j:
dp[i] = 1
dp[i] = max(dp[i], dp[i - j] + dp[j])
return dp[target] # 只會求出數量
```
2023/05/02,需要紀錄starting point,不然會有重複配對的問題
```python
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
def backtracking(remain, combination, start_index):
if remain == 0:
res.append(combination.copy())
return
if remain < 0:
return
# 要記錄starting point 不然會有重複配對的問題
# 規定只能往後配對
for i in range(start_index, len(candidates)):
combination.append(candidates[i])
backtracking(remain - candidates[i], combination, i)
combination.pop()
backtracking(target, [], 0)
return res
```
2023/07/10
永遠往後尋找,這樣就不會有重複的
1. 起始點永遠為自己(可重複) or 比自己更大的數
2. 需要starting point
3. path要remove,因為要還一個空的path給下一個數字
4. path需要被copy(),不然之後的跌代,此path就會變
```python
class Solution:
def __init__(self):
self.res = list()
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
def dfs(starting, total, path):
if total == target:
self.res.append(path.copy())
return
if total > target:
return
for i in range(starting, len(candidates)):
path.append(candidates[i])
dfs(i, total + candidates[i], path)
path.remove(candidates[i])
return
dfs(0, 0, [])
return self.res
```
2023/10/11
for i in range(starting, len(candidates)):
```python
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
def dfs(starting, total, path):
if total == target:
res.append(path.copy())
return
if total > target:
return
for i in range(starting, len(candidates)):
dfs(i, total + candidates[i], path + [candidates[i]])
return
for i, n in enumerate(candidates):
dfs(i, n, [n])
return res
```
2023/12/02
```python
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
def backtracking(starting, total, subRes):
if total == target:
res.append(subRes.copy())
return
if total > target:
return
for i in range(starting, len(candidates)):
n = candidates[i]
subRes.append(n)
backtracking(i, total + n, subRes)
subRes.remove(n)
return
backtracking(0, 0, list())
return res
```
2024/10/22
昨天收到google Taiwan面試,還好沒有放棄刷題,感謝在看不見希望還努力刷題的自己
```python
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
self.res = []
self.backtracking(candidates, target, [], 0)
return self.res
def backtracking(self, candidates, target, path, start):
if sum(path) == target:
self.res.append(path)
if sum(path) > target:
return
for i in range(start, len(candidates)):
self.backtracking(candidates, target, path + [candidates[i]], i)
```
2025/03/04
今天有一點被困住,想說在backtracking那部份,為什麼每一個都要加上n,考慮到當前的n,想說如果有些組何不用n呢。原因是因為,這些不同n會在for迴圈被考慮,例如[2,3,6,7],會有[2,6]的這個組合出現,在第一次考慮2後,第二次可以考慮[2,3,6,7],就會有[2,6]此組合出現
```python
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
self.backtracking(candidates, target, 0, 0, [], res)
return res
def backtracking(self, candidates, target, starting, total, path, res):
if total > target:
return
elif total == target:
res.append(path)
for i in range(starting, len(candidates)):
n = candidates[i]
self.backtracking(candidates, target, i, total + n, path + [n], res)
```
---
### **優化**
時間複雜度:O(N^target),其中 N 是 candidates 的數量,target 是目標值。每個元素都可以重複使用,因此有 N^target 種可能的組合。在最壞情況下,遞歸樹的高度為 target,因此需要總共的運行時間為 O(N^target)。
空間複雜度:O(target),因為我們需要在遞歸過程中存儲組合,並且最多有 target 層遞歸調用。此外,輸出數組 res 也需要 O(N^target) 的空間。
```python
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
def backtracking(remain, combination, start_index):
# 找到解法
if remain == 0:
# 可能是因為combination為[]在全域已被定義
# 所以copy可以把目前的combination抓住
res.append(combination.copy())
return
# 小於0不用繼續往下扣找
if remain < 0:
return
for i in range(start_index, len(candidates)):
combination.append(candidates[i])
# 自己可以重複(start_index)
backtracking(remain - candidates[i], combination, i)
# 如果都回傳完了(不管是否有append到res都會回傳)
# 那就繼續下一個i的組合
combination.pop()
backtracking(target, [], 0)
return res
```
---
**:warning: 錯誤語法**
:::warning
:::
**:thumbsup:學習**
:::success
若在函式中return後面沒有接東西,意思是:結束函式,因為沒有定義資料,所以回傳 None
一般 copy
三種方法
```python
b = list(a)
b = a[:]
b = a.copy()
```
:::
**思路**
**講解連結**
https://www.youtube.com/watch?v=GBKI9VSKdGg
https://ithelp.ithome.com.tw/articles/10286451
https://www.youtube.com/watch?v=7gcM8zyPtU4&ab_channel=Peter%E5%88%B7Leetcode
Provided by. NeetCode
###### tags: `dynamic programming` `medium` `leetcode`