@@ -296,24 +296,91 @@ class Solution {
296
296
```
297
297
298
298
## Python
299
- ``` python
299
+ ** 回溯+巧妙去重(省去使用used**
300
+ ``` python3
300
301
class Solution :
302
+ def __init__ (self ):
303
+ self .paths = []
304
+ self .path = []
305
+
306
+ def combinationSum2 (self , candidates : List[int ], target : int ) -> List[List[int ]]:
307
+ '''
308
+ 类似于求三数之和,求四数之和,为了避免重复组合,需要提前进行数组排序
309
+ '''
310
+ self .paths.clear()
311
+ self .path.clear()
312
+ # 必须提前进行数组排序,避免重复
313
+ candidates.sort()
314
+ self .backtracking(candidates, target, 0 , 0 )
315
+ return self .paths
316
+
317
+ def backtracking (self , candidates : List[int ], target : int , sum_ : int , start_index : int ) -> None :
318
+ # Base Case
319
+ if sum_ == target:
320
+ self .paths.append(self .path[:])
321
+ return
322
+
323
+ # 单层递归逻辑
324
+ for i in range (start_index, len (candidates)):
325
+ # 剪枝,同39.组合总和
326
+ if sum_ + candidates[i] > target:
327
+ return
328
+
329
+ # 跳过同一树层使用过的元素
330
+ if i > start_index and candidates[i] == candidates[i- 1 ]:
331
+ continue
332
+
333
+ sum_ += candidates[i]
334
+ self .path.append(candidates[i])
335
+ self .backtracking(candidates, target, sum_, i+ 1 )
336
+ self .path.pop() # 回溯,为了下一轮for loop
337
+ sum_ -= candidates[i] # 回溯,为了下一轮for loop
338
+ ```
339
+ ** 回溯+去重(使用used)**
340
+ ``` python3
341
+ class Solution :
342
+ def __init__ (self ):
343
+ self .paths = []
344
+ self .path = []
345
+ self .used = []
346
+
301
347
def combinationSum2 (self , candidates : List[int ], target : int ) -> List[List[int ]]:
302
- res = []
303
- path = []
304
- def backtrack (candidates ,target ,sum ,startIndex ):
305
- if sum == target: res.append(path[:])
306
- for i in range (startIndex,len (candidates)): # 要对同一树层使用过的元素进行跳过
307
- if sum + candidates[i] > target: return
308
- if i > startIndex and candidates[i] == candidates[i- 1 ]: continue # 直接用startIndex来去重,要对同一树层使用过的元素进行跳过
309
- sum += candidates[i]
310
- path.append(candidates[i])
311
- backtrack(candidates,target,sum ,i+ 1 ) # i+1:每个数字在每个组合中只能使用一次
312
- sum -= candidates[i] # 回溯
313
- path.pop() # 回溯
314
- candidates = sorted (candidates) # 首先把给candidates排序,让其相同的元素都挨在一起。
315
- backtrack(candidates,target,0 ,0 )
316
- return res
348
+ '''
349
+ 类似于求三数之和,求四数之和,为了避免重复组合,需要提前进行数组排序
350
+ 本题需要使用used,用来标记区别同一树层的元素使用重复情况:注意区分递归纵向遍历遇到的重复元素,和for循环遇到的重复元素,这两者的区别
351
+ '''
352
+ self .paths.clear()
353
+ self .path.clear()
354
+ self .usage_list = [False ] * len (candidates)
355
+ # 必须提前进行数组排序,避免重复
356
+ candidates.sort()
357
+ self .backtracking(candidates, target, 0 , 0 )
358
+ return self .paths
359
+
360
+ def backtracking (self , candidates : List[int ], target : int , sum_ : int , start_index : int ) -> None :
361
+ # Base Case
362
+ if sum_ == target:
363
+ self .paths.append(self .path[:])
364
+ return
365
+
366
+ # 单层递归逻辑
367
+ for i in range (start_index, len (candidates)):
368
+ # 剪枝,同39.组合总和
369
+ if sum_ + candidates[i] > target:
370
+ return
371
+
372
+ # 检查同一树层是否出现曾经使用过的相同元素
373
+ # 若数组中前后元素值相同,但前者却未被使用(used == False),说明是for loop中的同一树层的相同元素情况
374
+ if i > 0 and candidates[i] == candidates[i- 1 ] and self .usage_list[i- 1 ] == False :
375
+ continue
376
+
377
+ sum_ += candidates[i]
378
+ self .path.append(candidates[i])
379
+ self .usage_list[i] = True
380
+ self .backtracking(candidates, target, sum_, i+ 1 )
381
+ self .usage_list[i] = False # 回溯,为了下一轮for loop
382
+ self .path.pop() # 回溯,为了下一轮for loop
383
+ sum_ -= candidates[i] # 回溯,为了下一轮for loop
317
384
```
318
385
319
386
## Go:
0 commit comments