Merge pull request #2098 from jianghongcheng/master

修改py
This commit is contained in:
程序员Carl
2023-05-29 15:11:30 +08:00
committed by GitHub
19 changed files with 919 additions and 844 deletions

View File

@ -287,98 +287,153 @@ class Solution {
```
## Python
**回溯**
回溯
```python
class Solution:
def __init__(self):
self.answers: List[str] = []
self.answer: str = ''
self.letter_map = {
'2': 'abc',
'3': 'def',
'4': 'ghi',
'5': 'jkl',
'6': 'mno',
'7': 'pqrs',
'8': 'tuv',
'9': 'wxyz'
}
def letterCombinations(self, digits: str) -> List[str]:
self.answers.clear()
if not digits: return []
self.letterMap = [
"", # 0
"", # 1
"abc", # 2
"def", # 3
"ghi", # 4
"jkl", # 5
"mno", # 6
"pqrs", # 7
"tuv", # 8
"wxyz" # 9
]
self.result = []
self.s = ""
def backtracking(self, digits, index):
if index == len(digits):
self.result.append(self.s)
return
digit = int(digits[index]) # 将索引处的数字转换为整数
letters = self.letterMap[digit] # 获取对应的字符集
for i in range(len(letters)):
self.s += letters[i] # 处理字符
self.backtracking(digits, index + 1) # 递归调用注意索引加1处理下一个数字
self.s = self.s[:-1] # 回溯,删除最后添加的字符
def letterCombinations(self, digits):
if len(digits) == 0:
return self.result
self.backtracking(digits, 0)
return self.answers
def backtracking(self, digits: str, index: int) -> None:
# 回溯函数没有返回值
# Base Case
if index == len(digits): # 当遍历穷尽后的下一层时
self.answers.append(self.answer)
return
# 单层递归逻辑
letters: str = self.letter_map[digits[index]]
for letter in letters:
self.answer += letter # 处理
self.backtracking(digits, index + 1) # 递归至下一层
self.answer = self.answer[:-1] # 回溯
return self.result
```
**回溯简化**
回溯精简(版本一)
```python
class Solution:
def __init__(self):
self.answers: List[str] = []
self.letter_map = {
'2': 'abc',
'3': 'def',
'4': 'ghi',
'5': 'jkl',
'6': 'mno',
'7': 'pqrs',
'8': 'tuv',
'9': 'wxyz'
}
def letterCombinations(self, digits: str) -> List[str]:
self.answers.clear()
if not digits: return []
self.backtracking(digits, 0, '')
return self.answers
self.letterMap = [
"", # 0
"", # 1
"abc", # 2
"def", # 3
"ghi", # 4
"jkl", # 5
"mno", # 6
"pqrs", # 7
"tuv", # 8
"wxyz" # 9
]
self.result = []
def backtracking(self, digits: str, index: int, answer: str) -> None:
# 回溯函数没有返回值
# Base Case
if index == len(digits): # 当遍历穷尽后的下一层时
self.answers.append(answer)
return
# 单层递归逻辑
letters: str = self.letter_map[digits[index]]
def getCombinations(self, digits, index, s):
if index == len(digits):
self.result.append(s)
return
digit = int(digits[index])
letters = self.letterMap[digit]
for letter in letters:
self.backtracking(digits, index + 1, answer + letter) # 递归至下一层 + 回溯
self.getCombinations(digits, index + 1, s + letter)
def letterCombinations(self, digits):
if len(digits) == 0:
return self.result
self.getCombinations(digits, 0, "")
return self.result
```
**使用itertools**
回溯精简(版本二)
```python
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
import itertools
if not digits:
return list()
phoneMap = {
"2": "abc",
"3": "def",
"4": "ghi",
"5": "jkl",
"6": "mno",
"7": "pqrs",
"8": "tuv",
"9": "wxyz",
}
def __init__(self):
self.letterMap = [
"", # 0
"", # 1
"abc", # 2
"def", # 3
"ghi", # 4
"jkl", # 5
"mno", # 6
"pqrs", # 7
"tuv", # 8
"wxyz" # 9
]
def getCombinations(self, digits, index, s, result):
if index == len(digits):
result.append(s)
return
digit = int(digits[index])
letters = self.letterMap[digit]
for letter in letters:
self.getCombinations(digits, index + 1, s + letter, result)
def letterCombinations(self, digits):
result = []
if len(digits) == 0:
return result
self.getCombinations(digits, 0, "", result)
return result
groups = (phoneMap[digit] for digit in digits)
return ["".join(combination) for combination in itertools.product(*groups)]
```
回溯优化使用列表
```python
class Solution:
def __init__(self):
self.letterMap = [
"", # 0
"", # 1
"abc", # 2
"def", # 3
"ghi", # 4
"jkl", # 5
"mno", # 6
"pqrs", # 7
"tuv", # 8
"wxyz" # 9
]
def getCombinations(self, digits, index, path, result):
if index == len(digits):
result.append(''.join(path))
return
digit = int(digits[index])
letters = self.letterMap[digit]
for letter in letters:
path.append(letter)
self.getCombinations(digits, index + 1, path, result)
path.pop()
def letterCombinations(self, digits):
result = []
if len(digits) == 0:
return result
self.getCombinations(digits, 0, [], result)
return result
```
## Go

View File

@ -273,75 +273,101 @@ class Solution {
## Python
**回溯**
回溯(版本一)
```python
class Solution:
def __init__(self):
self.path = []
self.paths = []
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
'''
因为本题没有组合数量限制所以只要元素总和大于target就算结束
'''
self.path.clear()
self.paths.clear()
self.backtracking(candidates, target, 0, 0)
return self.paths
def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
# Base Case
if sum_ == target:
self.paths.append(self.path[:]) # 因为是shallow copy所以不能直接传入self.path
def backtracking(self, candidates, target, total, startIndex, path, result):
if total > target:
return
if sum_ > target:
if total == target:
result.append(path[:])
return
# 单层递归逻辑
for i in range(start_index, len(candidates)):
sum_ += candidates[i]
self.path.append(candidates[i])
self.backtracking(candidates, target, sum_, i) # 因为无限制重复选取所以不是i+1
sum_ -= candidates[i] # 回溯
self.path.pop() # 回溯
for i in range(startIndex, len(candidates)):
total += candidates[i]
path.append(candidates[i])
self.backtracking(candidates, target, total, i, path, result) # 不用i+1了表示可以重复读取当前的数
total -= candidates[i]
path.pop()
def combinationSum(self, candidates, target):
result = []
self.backtracking(candidates, target, 0, 0, [], result)
return result
```
**剪枝回溯**
回溯剪枝(版本一)
```python
class Solution:
def __init__(self):
self.path = []
self.paths = []
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
'''
因为本题没有组合数量限制所以只要元素总和大于target就算结束
'''
self.path.clear()
self.paths.clear()
# 为了剪枝需要提前进行排序
candidates.sort()
self.backtracking(candidates, target, 0, 0)
return self.paths
def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
# Base Case
if sum_ == target:
self.paths.append(self.path[:]) # 因为是shallow copy所以不能直接传入self.path
def backtracking(self, candidates, target, total, startIndex, path, result):
if total == target:
result.append(path[:])
return
# 单层递归逻辑
# 如果本层 sum + condidates[i] > target就提前结束遍历剪枝
for i in range(start_index, len(candidates)):
if sum_ + candidates[i] > target:
return
sum_ += candidates[i]
self.path.append(candidates[i])
self.backtracking(candidates, target, sum_, i) # 因为无限制重复选取所以不是i-1
sum_ -= candidates[i] # 回溯
self.path.pop() # 回溯
for i in range(startIndex, len(candidates)):
if total + candidates[i] > target:
break
total += candidates[i]
path.append(candidates[i])
self.backtracking(candidates, target, total, i, path, result)
total -= candidates[i]
path.pop()
def combinationSum(self, candidates, target):
result = []
candidates.sort() # 需要排序
self.backtracking(candidates, target, 0, 0, [], result)
return result
```
回溯(版本二)
```python
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
result =[]
self.backtracking(candidates, target, 0, [], result)
return result
def backtracking(self, candidates, target, startIndex, path, result):
if target == 0:
result.append(path[:])
return
if target < 0:
return
for i in range(startIndex, len(candidates)):
path.append(candidates[i])
self.backtracking(candidates, target - candidates[i], i, path, result)
path.pop()
```
回溯剪枝(版本二)
```python
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
result =[]
candidates.sort()
self.backtracking(candidates, target, 0, [], result)
return result
def backtracking(self, candidates, target, startIndex, path, result):
if target == 0:
result.append(path[:])
return
for i in range(startIndex, len(candidates)):
if target - candidates[i] < 0:
break
path.append(candidates[i])
self.backtracking(candidates, target - candidates[i], i, path, result)
path.pop()
```
## Go

View File

@ -356,93 +356,92 @@ class Solution {
```
## Python
**回溯+巧妙去重(省去使用used**
回溯
```python
class Solution:
def __init__(self):
self.paths = []
self.path = []
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
'''
类似于求三数之和,求四数之和,为了避免重复组合,需要提前进行数组排序
'''
self.paths.clear()
self.path.clear()
# 必须提前进行数组排序,避免重复
candidates.sort()
self.backtracking(candidates, target, 0, 0)
return self.paths
def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
# Base Case
if sum_ == target:
self.paths.append(self.path[:])
def backtracking(self, candidates, target, total, startIndex, path, result):
if total == target:
result.append(path[:])
return
# 单层递归逻辑
for i in range(start_index, len(candidates)):
# 剪枝同39.组合总和
if sum_ + candidates[i] > target:
return
# 跳过同一树层使用过的元素
if i > start_index and candidates[i] == candidates[i-1]:
for i in range(startIndex, len(candidates)):
if i > startIndex and candidates[i] == candidates[i - 1]:
continue
sum_ += candidates[i]
self.path.append(candidates[i])
self.backtracking(candidates, target, sum_, i+1)
self.path.pop() # 回溯为了下一轮for loop
sum_ -= candidates[i] # 回溯为了下一轮for loop
if total + candidates[i] > target:
break
total += candidates[i]
path.append(candidates[i])
self.backtracking(candidates, target, total, i + 1, path, result)
total -= candidates[i]
path.pop()
def combinationSum2(self, candidates, target):
result = []
candidates.sort()
self.backtracking(candidates, target, 0, 0, [], result)
return result
```
**回溯+去重(使用used**
回溯 使用used
```python
class Solution:
def __init__(self):
self.paths = []
self.path = []
self.used = []
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
'''
类似于求三数之和,求四数之和,为了避免重复组合,需要提前进行数组排序
本题需要使用used用来标记区别同一树层的元素使用重复情况注意区分递归纵向遍历遇到的重复元素和for循环遇到的重复元素这两者的区别
'''
self.paths.clear()
self.path.clear()
self.usage_list = [False] * len(candidates)
# 必须提前进行数组排序,避免重复
candidates.sort()
self.backtracking(candidates, target, 0, 0)
return self.paths
def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
# Base Case
if sum_ == target:
self.paths.append(self.path[:])
def backtracking(self, candidates, target, total, startIndex, used, path, result):
if total == target:
result.append(path[:])
return
# 单层递归逻辑
for i in range(start_index, len(candidates)):
# 剪枝同39.组合总和
if sum_ + candidates[i] > target:
return
# 检查同一树层是否出现曾经使用过的相同元素
# 若数组中前后元素值相同,但前者却未被使用(used == False)说明是for loop中的同一树层的相同元素情况
if i > 0 and candidates[i] == candidates[i-1] and self.usage_list[i-1] == False:
for i in range(startIndex, len(candidates)):
# 对于相同的数字,只选择第一个未被使用的数字,跳过其他相同数字
if i > startIndex and candidates[i] == candidates[i - 1] and not used[i - 1]:
continue
sum_ += candidates[i]
self.path.append(candidates[i])
self.usage_list[i] = True
self.backtracking(candidates, target, sum_, i+1)
self.usage_list[i] = False # 回溯为了下一轮for loop
self.path.pop() # 回溯为了下一轮for loop
sum_ -= candidates[i] # 回溯为了下一轮for loop
```
if total + candidates[i] > target:
break
total += candidates[i]
path.append(candidates[i])
used[i] = True
self.backtracking(candidates, target, total, i + 1, used, path, result)
used[i] = False
total -= candidates[i]
path.pop()
def combinationSum2(self, candidates, target):
used = [False] * len(candidates)
result = []
candidates.sort()
self.backtracking(candidates, target, 0, 0, used, [], result)
return result
```
回溯优化
```python
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
candidates.sort()
results = []
self.combinationSumHelper(candidates, target, 0, [], results)
return results
def combinationSumHelper(self, candidates, target, index, path, results):
if target == 0:
results.append(path[:])
return
for i in range(index, len(candidates)):
if i > index and candidates[i] == candidates[i - 1]:
continue
if candidates[i] > target:
break
path.append(candidates[i])
self.combinationSumHelper(candidates, target - candidates[i], i + 1, path, results)
path.pop()
```
## Go
主要在于如何在回溯中去重

View File

@ -215,68 +215,27 @@ class Solution {
```
### Python
**回溯**
回溯 使用used
```python
class Solution:
def __init__(self):
self.path = []
self.paths = []
def permute(self, nums):
result = []
self.backtracking(nums, [], [False] * len(nums), result)
return result
def permute(self, nums: List[int]) -> List[List[int]]:
'''
因为本题排列是有序的,这意味着同一层的元素可以重复使用,但同一树枝上不能重复使用(usage_list)
所以处理排列问题每层都需要从头搜索故不再使用start_index
'''
usage_list = [False] * len(nums)
self.backtracking(nums, usage_list)
return self.paths
def backtracking(self, nums: List[int], usage_list: List[bool]) -> None:
# Base Case本题求叶子节点
if len(self.path) == len(nums):
self.paths.append(self.path[:])
def backtracking(self, nums, path, used, result):
if len(path) == len(nums):
result.append(path[:])
return
# 单层递归逻辑
for i in range(0, len(nums)): # 从头开始搜索
# 若遇到self.path里已收录的元素跳过
if usage_list[i] == True:
for i in range(len(nums)):
if used[i]:
continue
usage_list[i] = True
self.path.append(nums[i])
self.backtracking(nums, usage_list) # 纵向传递使用信息,去重
self.path.pop()
usage_list[i] = False
```
**回溯+丢掉usage_list**
```python
class Solution:
def __init__(self):
self.path = []
self.paths = []
used[i] = True
path.append(nums[i])
self.backtracking(nums, path, used, result)
path.pop()
used[i] = False
def permute(self, nums: List[int]) -> List[List[int]]:
'''
因为本题排列是有序的,这意味着同一层的元素可以重复使用,但同一树枝上不能重复使用
所以处理排列问题每层都需要从头搜索故不再使用start_index
'''
self.backtracking(nums)
return self.paths
def backtracking(self, nums: List[int]) -> None:
# Base Case本题求叶子节点
if len(self.path) == len(nums):
self.paths.append(self.path[:])
return
# 单层递归逻辑
for i in range(0, len(nums)): # 从头开始搜索
# 若遇到self.path里已收录的元素跳过
if nums[i] in self.path:
continue
self.path.append(nums[i])
self.backtracking(nums)
self.path.pop()
```
### Go

View File

@ -223,28 +223,25 @@ class Solution {
```python
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
# res用来存放结果
if not nums: return []
res = []
used = [0] * len(nums)
def backtracking(nums, used, path):
# 终止条件
if len(path) == len(nums):
res.append(path.copy())
return
for i in range(len(nums)):
if not used[i]:
if i>0 and nums[i] == nums[i-1] and not used[i-1]:
continue
used[i] = 1
path.append(nums[i])
backtracking(nums, used, path)
path.pop()
used[i] = 0
# 记得给nums排序
backtracking(sorted(nums),used,[])
return res
def permuteUnique(self, nums):
nums.sort() # 排序
result = []
self.backtracking(nums, [], [False] * len(nums), result)
return result
def backtracking(self, nums, path, used, result):
if len(path) == len(nums):
result.append(path[:])
return
for i in range(len(nums)):
if (i > 0 and nums[i] == nums[i - 1] and not used[i - 1]) or used[i]:
continue
used[i] = True
path.append(nums[i])
self.backtracking(nums, path, used, result)
path.pop()
used[i] = False
```
### Go

View File

@ -351,48 +351,47 @@ class Solution {
```python
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
if not n: return []
board = [['.'] * n for _ in range(n)]
res = []
def isVaild(board,row, col):
#判断同一列是否冲突
for i in range(len(board)):
if board[i][col] == 'Q':
return False
# 判断左上角是否冲突
i = row -1
j = col -1
while i>=0 and j>=0:
if board[i][j] == 'Q':
return False
i -= 1
j -= 1
# 判断右上角是否冲突
i = row - 1
j = col + 1
while i>=0 and j < len(board):
if board[i][j] == 'Q':
return False
i -= 1
j += 1
return True
result = [] # 存储最终结果的二维字符串数组
chessboard = ['.' * n for _ in range(n)] # 初始化棋盘
self.backtracking(n, 0, chessboard, result) # 回溯求解
return [[''.join(row) for row in solution] for solution in result] # 返回结果集
def backtracking(self, n: int, row: int, chessboard: List[str], result: List[List[str]]) -> None:
if row == n:
result.append(chessboard[:]) # 棋盘填满,将当前解加入结果集
return
for col in range(n):
if self.isValid(row, col, chessboard):
chessboard[row] = chessboard[row][:col] + 'Q' + chessboard[row][col+1:] # 放置皇后
self.backtracking(n, row + 1, chessboard, result) # 递归到下一行
chessboard[row] = chessboard[row][:col] + '.' + chessboard[row][col+1:] # 回溯,撤销当前位置的皇后
def isValid(self, row: int, col: int, chessboard: List[str]) -> bool:
# 检查列
for i in range(row):
if chessboard[i][col] == 'Q':
return False # 当前列已经存在皇后,不合法
# 检查 45 度角是否有皇后
i, j = row - 1, col - 1
while i >= 0 and j >= 0:
if chessboard[i][j] == 'Q':
return False # 左上方向已经存在皇后,不合法
i -= 1
j -= 1
# 检查 135 度角是否有皇后
i, j = row - 1, col + 1
while i >= 0 and j < len(chessboard):
if chessboard[i][j] == 'Q':
return False # 右上方向已经存在皇后,不合法
i -= 1
j += 1
return True # 当前位置合法
def backtracking(board, row, n):
# 如果走到最后一行,说明已经找到一个解
if row == n:
temp_res = []
for temp in board:
temp_str = "".join(temp)
temp_res.append(temp_str)
res.append(temp_res)
for col in range(n):
if not isVaild(board, row, col):
continue
board[row][col] = 'Q'
backtracking(board, row+1, n)
board[row][col] = '.'
backtracking(board, 0, n)
return res
```

View File

@ -381,68 +381,42 @@ class Solution {
```
### Python
未剪枝优化
```python
class Solution(object):
def combine(self, n, k):
"""
:type n: int
:type k: int
:rtype: List[List[int]]
"""
result = []
path = []
def backtracking(n, k, startidx):
if len(path) == k:
result.append(path[:])
return
# 剪枝, 最后k - len(path)个节点直接构造结果,无需递归
last_startidx = n - (k - len(path)) + 1
for x in range(startidx, last_startidx + 1):
path.append(x)
backtracking(n, k, x + 1) # 递归
path.pop() # 回溯
backtracking(n, k, 1)
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
result = [] # 存放结果集
self.backtracking(n, k, 1, [], result)
return result
def backtracking(self, n, k, startIndex, path, result):
if len(path) == k:
result.append(path[:])
return
for i in range(startIndex, n + 1): # 需要优化的地方
path.append(i) # 处理节点
self.backtracking(n, k, i + 1, path, result)
path.pop() # 回溯,撤销处理的节点
```
剪枝优化:
```python
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
res = []
path = []
def backtrack(n, k, StartIndex):
if len(path) == k:
res.append(path[:])
return
for i in range(StartIndex, n + 1):
path.append(i)
backtrack(n, k, i+1)
path.pop()
backtrack(n, k, 1)
return res
```
result = [] # 存放结果集
self.backtracking(n, k, 1, [], result)
return result
def backtracking(self, n, k, startIndex, path, result):
if len(path) == k:
result.append(path[:])
return
for i in range(startIndex, n - (k - len(path)) + 2): # 优化的地方
path.append(i) # 处理节点
self.backtracking(n, k, i + 1, path, result)
path.pop() # 回溯,撤销处理的节点
剪枝:
```python
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
res=[] #存放符合条件结果的集合
path=[] #用来存放符合条件结果
def backtrack(n,k,startIndex):
if len(path) == k:
res.append(path[:])
return
for i in range(startIndex,n-(k-len(path))+2): #优化的地方
path.append(i) #处理节点
backtrack(n,k,i+1) #递归
path.pop() #回溯,撤销处理的节点
backtrack(n,k,1)
return res
```
### Go

View File

@ -183,18 +183,21 @@ Python
```python
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
res=[] #存放符合条件结果的集合
path=[] #用来存放符合条件结果
def backtrack(n,k,startIndex):
if len(path) == k:
res.append(path[:])
return
for i in range(startIndex,n-(k-len(path))+2): #优化的地方
path.append(i) #处理节点
backtrack(n,k,i+1) #递归
path.pop() #回溯,撤销处理的节点
backtrack(n,k,1)
return res
result = [] # 存放结果集
self.backtracking(n, k, 1, [], result)
return result
def backtracking(self, n, k, startIndex, path, result):
if len(path) == k:
result.append(path[:])
return
for i in range(startIndex, n - (k - len(path)) + 2): # 优化的地方
path.append(i) # 处理节点
self.backtracking(n, k, i + 1, path, result)
path.pop() # 回溯,撤销处理的节点
```
Go
```Go

View File

@ -208,28 +208,20 @@ class Solution {
## Python
```python
class Solution:
def __init__(self):
self.path: List[int] = []
self.paths: List[List[int]] = []
def subsets(self, nums):
result = []
path = []
self.backtracking(nums, 0, path, result)
return result
def subsets(self, nums: List[int]) -> List[List[int]]:
self.paths.clear()
self.path.clear()
self.backtracking(nums, 0)
return self.paths
def backtracking(self, nums: List[int], start_index: int) -> None:
# 收集子集,要先于终止判断
self.paths.append(self.path[:])
# Base Case
if start_index == len(nums):
return
# 单层递归逻辑
for i in range(start_index, len(nums)):
self.path.append(nums[i])
self.backtracking(nums, i+1)
self.path.pop() # 回溯
def backtracking(self, nums, startIndex, path, result):
result.append(path[:]) # 收集子集,要放在终止添加的上面,否则会漏掉自己
# if startIndex >= len(nums): # 终止条件可以不加
# return
for i in range(startIndex, len(nums)):
path.append(nums[i])
self.backtracking(nums, i + 1, path, result)
path.pop()
```
## Go

View File

@ -238,86 +238,84 @@ class Solution {
}
```
### Python
```python
class Solution:
def __init__(self):
self.paths = []
self.path = []
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
nums.sort()
self.backtracking(nums, 0)
return self.paths
def backtracking(self, nums: List[int], start_index: int) -> None:
# ps.空集合仍符合要求
self.paths.append(self.path[:])
# Base Case
if start_index == len(nums):
return
# 单层递归逻辑
for i in range(start_index, len(nums)):
if i > start_index and nums[i] == nums[i-1]:
# 当前后元素值相同时,跳入下一个循环,去重
continue
self.path.append(nums[i])
self.backtracking(nums, i+1)
self.path.pop()
```
#### Python3
不使用used数组
回溯 利用used数组去重
```python
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
res = []
path = []
nums.sort() # 去重需要先对数组进行排序
def backtracking(nums, startIndex):
# 终止条件
res.append(path[:])
if startIndex == len(nums):
return
# for循环
for i in range(startIndex, len(nums)):
# 数层去重
if i > startIndex and nums[i] == nums[i-1]: # 去重
continue
path.append(nums[i])
backtracking(nums, i+1)
path.pop()
backtracking(nums, 0)
return res
```
使用used数组
```python
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
def subsetsWithDup(self, nums):
result = []
path = []
nums.sort()
used = [0] * len(nums)
def backtrack(nums, startIdx):
result.append(path[:])
for i in range(startIdx, len(nums)):
if i > startIdx and nums[i] == nums[i-1] and used[i-1] == 0:
continue
used[i] = 1
path.append(nums[i])
backtrack(nums, i+1)
path.pop()
used[i] = 0
backtrack(nums, 0)
used = [False] * len(nums)
nums.sort() # 去重需要排序
self.backtracking(nums, 0, used, path, result)
return result
def backtracking(self, nums, startIndex, used, path, result):
result.append(path[:]) # 收集子集
for i in range(startIndex, len(nums)):
# used[i - 1] == True说明同一树枝 nums[i - 1] 使用过
# used[i - 1] == False说明同一树层 nums[i - 1] 使用过
# 而我们要对同一树层使用过的元素进行跳过
if i > 0 and nums[i] == nums[i - 1] and not used[i - 1]:
continue
path.append(nums[i])
used[i] = True
self.backtracking(nums, i + 1, used, path, result)
used[i] = False
path.pop()
```
回溯 利用集合去重
```python
class Solution:
def subsetsWithDup(self, nums):
result = []
path = []
nums.sort() # 去重需要排序
self.backtracking(nums, 0, path, result)
return result
def backtracking(self, nums, startIndex, path, result):
result.append(path[:]) # 收集子集
uset = set()
for i in range(startIndex, len(nums)):
if nums[i] in uset:
continue
uset.add(nums[i])
path.append(nums[i])
self.backtracking(nums, i + 1, path, result)
path.pop()
```
回溯 利用递归的时候下一个startIndex是i+1而不是0去重
```python
class Solution:
def subsetsWithDup(self, nums):
result = []
path = []
nums.sort() # 去重需要排序
self.backtracking(nums, 0, path, result)
return result
def backtracking(self, nums, startIndex, path, result):
result.append(path[:]) # 收集子集
for i in range(startIndex, len(nums)):
# 而我们要对同一树层使用过的元素进行跳过
if i > startIndex and nums[i] == nums[i - 1]:
continue
path.append(nums[i])
self.backtracking(nums, i + 1, path, result)
path.pop()
```
### Go
```Go

View File

@ -362,104 +362,82 @@ class Solution {
## python
python2:
```python
class Solution(object):
def restoreIpAddresses(self, s):
"""
:type s: str
:rtype: List[str]
"""
ans = []
path = []
def backtrack(path, startIndex):
if len(s) > 12: return []
if len(path) == 4:
if startIndex == len(s):
ans.append(".".join(path[:]))
return
for i in range(startIndex+1, min(startIndex+4, len(s)+1)): # 剪枝
string = s[startIndex:i]
if not 0 <= int(string) <= 255:
continue
if not string == "0" and not string.lstrip('0') == string:
continue
path.append(string)
backtrack(path, i)
path.pop()
backtrack([], 0)
return ans
```
python3:
回溯(版本一)
```python
class Solution:
def __init__(self):
self.result = []
def restoreIpAddresses(self, s: str) -> List[str]:
'''
本质切割问题使用回溯搜索法,本题只能切割三次,所以纵向递归总共四层
因为不能重复分割所以需要start_index来记录下一层递归分割的起始位置
添加变量point_num来记录逗号的数量[0,3]
'''
self.result.clear()
if len(s) > 12: return []
self.backtracking(s, 0, 0)
return self.result
result = []
self.backtracking(s, 0, 0, "", result)
return result
def backtracking(self, s: str, start_index: int, point_num: int) -> None:
# Base Case
if point_num == 3:
if self.is_valid(s, start_index, len(s)-1):
self.result.append(s[:])
def backtracking(self, s, start_index, point_num, current, result):
if point_num == 3: # 逗点数量为3时分隔结束
if self.is_valid(s, start_index, len(s) - 1): # 判断第四段子字符串是否合法
current += s[start_index:] # 添加最后一段子字符串
result.append(current)
return
# 单层递归逻辑
for i in range(start_index, len(s)):
# [start_index, i]就是被截取的子串
if self.is_valid(s, start_index, i):
s = s[:i+1] + '.' + s[i+1:]
self.backtracking(s, i+2, point_num+1) # 在填入.后下一子串起始后移2位
s = s[:i+1] + s[i+2:] # 回溯
else:
# 若当前被截取的子串大于255或者大于三位数直接结束本层循环
break
def is_valid(self, s: str, start: int, end: int) -> bool:
if start > end: return False
# 若数字是0开头不合法
if s[start] == '0' and start != end:
return False
if not 0 <= int(s[start:end+1]) <= 255:
return False
return True
```
python3; 简单拼接版本类似Leetcode131写法
for i in range(start_index, len(s)):
if self.is_valid(s, start_index, i): # 判断 [start_index, i] 这个区间的子串是否合法
sub = s[start_index:i + 1]
self.backtracking(s, i + 1, point_num + 1, current + sub + '.', result)
else:
break
def is_valid(self, s, start, end):
if start > end:
return False
if s[start] == '0' and start != end: # 0开头的数字不合法
return False
num = 0
for i in range(start, end + 1):
if not s[i].isdigit(): # 遇到非数字字符不合法
return False
num = num * 10 + int(s[i])
if num > 255: # 如果大于255了不合法
return False
return True
```
回溯(版本二)
```python
class Solution:
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
global results, path
results = []
path = []
self.backtracking(s,0)
self.backtracking(s, 0, [], results)
return results
def backtracking(self,s,index):
global results,path
if index == len(s) and len(path)==4:
results.append('.'.join(path)) # 在连接时需要中间间隔符号的话就在''中间写上对应的间隔符
def backtracking(self, s, index, path, results):
if index == len(s) and len(path) == 4:
results.append('.'.join(path))
return
for i in range(index,len(s)):
if len(path)>3: break # 剪枝
temp = s[index:i+1]
if (int(temp)<256 and int(temp)>0 and temp[0]!='0') or (temp=='0'):
path.append(temp)
self.backtracking(s,i+1)
path.pop()
if len(path) > 4: # 剪枝
return
for i in range(index, min(index + 3, len(s))):
if self.is_valid(s, index, i):
sub = s[index:i+1]
path.append(sub)
self.backtracking(s, i+1, path, results)
path.pop()
def is_valid(self, s, start, end):
if start > end:
return False
if s[start] == '0' and start != end: # 0开头的数字不合法
return False
num = int(s[start:end+1])
return 0 <= num <= 255
```
## Go
```go

View File

@ -352,12 +352,9 @@ class Solution {
```
## Python
**回溯+正反序判断回文串**
回溯 基本版
```python
class Solution:
def __init__(self):
self.paths = []
self.path = []
def partition(self, s: str) -> List[List[str]]:
'''
@ -366,52 +363,14 @@ class Solution:
当切割线迭代至字符串末尾,说明找到一种方法
类似组合问题为了不重复切割同一位置需要start_index来做标记下一轮递归的起始位置(切割线)
'''
self.path.clear()
self.paths.clear()
self.backtracking(s, 0)
return self.paths
result = []
self.backtracking(s, 0, [], result)
return result
def backtracking(self, s: str, start_index: int) -> None:
def backtracking(self, s, start_index, path, result ):
# Base Case
if start_index >= len(s):
self.paths.append(self.path[:])
return
# 单层递归逻辑
for i in range(start_index, len(s)):
# 此次比其他组合题目多了一步判断:
# 判断被截取的这一段子串([start_index, i])是否为回文串
temp = s[start_index:i+1]
if temp == temp[::-1]: # 若反序和正序相同,意味着这是回文串
self.path.append(temp)
self.backtracking(s, i+1) # 递归纵向遍历:从下一处进行切割,判断其余是否仍为回文串
self.path.pop()
else:
continue
```
**回溯+函数判断回文串**
```python
class Solution:
def __init__(self):
self.paths = []
self.path = []
def partition(self, s: str) -> List[List[str]]:
'''
递归用于纵向遍历
for循环用于横向遍历
当切割线迭代至字符串末尾,说明找到一种方法
类似组合问题为了不重复切割同一位置需要start_index来做标记下一轮递归的起始位置(切割线)
'''
self.path.clear()
self.paths.clear()
self.backtracking(s, 0)
return self.paths
def backtracking(self, s: str, start_index: int) -> None:
# Base Case
if start_index >= len(s):
self.paths.append(self.path[:])
if start_index == len(s):
result.append(path[:])
return
# 单层递归逻辑
@ -419,11 +378,10 @@ class Solution:
# 此次比其他组合题目多了一步判断:
# 判断被截取的这一段子串([start_index, i])是否为回文串
if self.is_palindrome(s, start_index, i):
self.path.append(s[start_index:i+1])
self.backtracking(s, i+1) # 递归纵向遍历:从下一处进行切割,判断其余是否仍为回文串
self.path.pop() # 回溯
else:
continue
path.append(s[start_index:i+1])
self.backtracking(s, i+1, path, result) # 递归纵向遍历:从下一处进行切割,判断其余是否仍为回文串
path.pop() # 回溯
def is_palindrome(self, s: str, start: int, end: int) -> bool:
i: int = start
@ -433,9 +391,88 @@ class Solution:
return False
i += 1
j -= 1
return True
return True
```
回溯+优化判定回文函数
```python
class Solution:
def partition(self, s: str) -> List[List[str]]:
result = []
self.backtracking(s, 0, [], result)
return result
def backtracking(self, s, start_index, path, result ):
# Base Case
if start_index == len(s):
result.append(path[:])
return
# 单层递归逻辑
for i in range(start_index, len(s)):
# 若反序和正序相同,意味着这是回文串
if s[start_index: i + 1] == s[start_index: i + 1][::-1]:
path.append(s[start_index:i+1])
self.backtracking(s, i+1, path, result) # 递归纵向遍历:从下一处进行切割,判断其余是否仍为回文串
path.pop() # 回溯
```
回溯+高效判断回文子串
```python
class Solution:
def partition(self, s: str) -> List[List[str]]:
result = []
isPalindrome = [[False] * len(s) for _ in range(len(s))] # 初始化isPalindrome矩阵
self.computePalindrome(s, isPalindrome)
self.backtracking(s, 0, [], result, isPalindrome)
return result
def backtracking(self, s, startIndex, path, result, isPalindrome):
if startIndex >= len(s):
result.append(path[:])
return
for i in range(startIndex, len(s)):
if isPalindrome[startIndex][i]: # 是回文子串
substring = s[startIndex:i + 1]
path.append(substring)
self.backtracking(s, i + 1, path, result, isPalindrome) # 寻找i+1为起始位置的子串
path.pop() # 回溯过程,弹出本次已经填在的子串
def computePalindrome(self, s, isPalindrome):
for i in range(len(s) - 1, -1, -1): # 需要倒序计算保证在i行时i+1行已经计算好了
for j in range(i, len(s)):
if j == i:
isPalindrome[i][j] = True
elif j - i == 1:
isPalindrome[i][j] = (s[i] == s[j])
else:
isPalindrome[i][j] = (s[i] == s[j] and isPalindrome[i+1][j-1])
```
回溯+使用all函数判断回文子串
```python
class Solution:
def partition(self, s: str) -> List[List[str]]:
result = []
self.partition_helper(s, 0, [], result)
return result
def partition_helper(self, s, start_index, path, result):
if start_index == len(s):
result.append(path[:])
return
for i in range(start_index + 1, len(s) + 1):
sub = s[start_index:i]
if self.isPalindrome(sub):
path.append(sub)
self.partition_helper(s, i, path, result)
path.pop()
def isPalindrome(self, s):
return all(s[i] == s[len(s) - 1 - i] for i in range(len(s) // 2))
```
## Go
```go
var (

View File

@ -362,28 +362,25 @@ class Solution {
```py
class Solution:
def __init__(self):
self.res = []
self.sum_now = 0
self.path = []
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
result = [] # 存放结果集
self.backtracking(n, k, 0, 1, [], result)
return result
def combinationSum3(self, k: int, n: int) -> [[int]]:
self.backtracking(k, n, 1)
return self.res
def backtracking(self, targetSum, k, currentSum, startIndex, path, result):
if currentSum > targetSum: # 剪枝操作
return # 如果path的长度等于k但currentSum不等于targetSum则直接返回
if len(path) == k:
if currentSum == targetSum:
result.append(path[:])
return
for i in range(startIndex, 9 - (k - len(path)) + 2): # 剪枝
currentSum += i # 处理
path.append(i) # 处理
self.backtracking(targetSum, k, currentSum, i + 1, path, result) # 注意i+1调整startIndex
currentSum -= i # 回溯
path.pop() # 回溯
def backtracking(self, k: int, n: int, start_num: int):
if self.sum_now > n: # 剪枝
return
if len(self.path) == k: # len(path)==k时不管sum是否等于n都会返回
if self.sum_now == n:
self.res.append(self.path[:])
return
for i in range(start_num, 10 - (k - len(self.path)) + 1):
self.path.append(i)
self.sum_now += i
self.backtracking(k, n, i + 1)
self.path.pop()
self.sum_now -= i
```
## Go

View File

@ -347,64 +347,88 @@ class Solution {
```
### python
回溯 使用used数组
```python
class Solution:
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
# defaultdic(list) 是为了方便直接append
tickets_dict = defaultdict(list)
for item in tickets:
tickets_dict[item[0]].append(item[1])
# 给每一个机场的到达机场排序小的在前面在回溯里首先被pop(0出去
# 这样最先找的的path就是排序最小的答案直接返回
for airport in tickets_dict: tickets_dict[airport].sort()
'''
tickets_dict里面的内容是这样的
{'JFK': ['ATL', 'SFO'], 'SFO': ['ATL'], 'ATL': ['JFK', 'SFO']})
'''
path = ["JFK"]
def backtracking(start_point):
# 终止条件
if len(path) == len(tickets) + 1:
return True
for _ in tickets_dict[start_point]:
#必须及时删除,避免出现死循环
end_point = tickets_dict[start_point].pop(0)
path.append(end_point)
# 只要找到一个就可以返回了
if backtracking(end_point):
return True
path.pop()
tickets_dict[start_point].append(end_point)
backtracking("JFK")
return path
```
python - 使用used数组 - 神似之前几题写法
```python
class Solution:
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
global used,path,results
used = [0]*len(tickets)
tickets.sort() # 先排序,这样一旦找到第一个可行路径,一定是字母排序最小的
used = [0] * len(tickets)
path = ['JFK']
results = []
tickets.sort() # 先排序,这样一旦找到第一个可行路径,一定是字母排序最小的
self.backtracking(tickets,'JFK')
self.backtracking(tickets, used, path, 'JFK', results)
return results[0]
def backtracking(self,tickets,cur):
if sum(used) == len(tickets):
results.append(path[:])
return True # 只要找到就返回
for i in range(len(tickets)):
if tickets[i][0]==cur and used[i]==0:
used[i]=1
path.append(tickets[i][1])
state = self.backtracking(tickets,tickets[i][1])
path.pop()
used[i]=0
if state: return True # 只要找到就返回,不继续搜索了
def backtracking(self, tickets, used, path, cur, results):
if len(path) == len(tickets) + 1: # 终止条件:路径长度等于机票数量+1
results.append(path[:]) # 将当前路径添加到结果列表
return True
for i, ticket in enumerate(tickets): # 遍历机票列表
if ticket[0] == cur and used[i] == 0: # 找到起始机场为cur且未使用过的机票
used[i] = 1 # 标记该机票为已使用
path.append(ticket[1]) # 将到达机场添加到路径中
state = self.backtracking(tickets, used, path, ticket[1], results) # 递归搜索
path.pop() # 回溯,移除最后添加的到达机场
used[i] = 0 # 标记该机票为未使用
if state:
return True # 只要找到一个可行路径就返回,不继续搜索
```
回溯 使用字典
```python
from collections import defaultdict
class Solution:
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
targets = defaultdict(list) # 构建机场字典
for ticket in tickets:
targets[ticket[0]].append(ticket[1])
for airport in targets:
targets[airport].sort() # 对目的地列表进行排序
path = ["JFK"] # 起始机场为"JFK"
self.backtracking(targets, path, len(tickets))
return path
def backtracking(self, targets, path, ticketNum):
if len(path) == ticketNum + 1:
return True # 找到有效行程
airport = path[-1] # 当前机场
destinations = targets[airport] # 当前机场可以到达的目的地列表
for i, dest in enumerate(destinations):
targets[airport].pop(i) # 标记已使用的机票
path.append(dest) # 添加目的地到路径
if self.backtracking(targets, path, ticketNum):
return True # 找到有效行程
targets[airport].insert(i, dest) # 回溯,恢复机票
path.pop() # 移除目的地
return False # 没有找到有效行程
```
回溯 使用字典 逆序
```python
from collections import defaultdict
class Solution:
def findItinerary(self, tickets):
targets = defaultdict(list) # 创建默认字典,用于存储机场映射关系
for ticket in tickets:
targets[ticket[0]].append(ticket[1]) # 将机票输入到字典中
for key in targets:
targets[key].sort(reverse=True) # 对到达机场列表进行字母逆序排序
result = []
self.backtracking("JFK", targets, result) # 调用回溯函数开始搜索路径
return result[::-1] # 返回逆序的行程路径
def backtracking(self, airport, targets, result):
while targets[airport]: # 当机场还有可到达的机场时
next_airport = targets[airport].pop() # 弹出下一个机场
self.backtracking(next_airport, targets, result) # 递归调用回溯函数进行深度优先搜索
result.append(airport) # 将当前机场添加到行程路径中
```
### GO

View File

@ -305,21 +305,43 @@ class Solution {
### Python
**贪心**
贪心版本一
```python
class Solution:
def wiggleMaxLength(self, nums):
if len(nums) <= 1:
return len(nums) # 如果数组长度为0或1则返回数组长度
curDiff = 0 # 当前一对元素的差值
preDiff = 0 # 前一对元素的差值
result = 1 # 记录峰值的个数初始为1默认最右边的元素被视为峰值
for i in range(len(nums) - 1):
curDiff = nums[i + 1] - nums[i] # 计算下一个元素与当前元素的差值
# 如果遇到一个峰值
if (preDiff <= 0 and curDiff > 0) or (preDiff >= 0 and curDiff < 0):
result += 1 # 峰值个数加1
preDiff = curDiff # 注意这里只在摆动变化的时候更新preDiff
return result # 返回最长摆动子序列的长度
```
贪心版本二
```python
class Solution:
def wiggleMaxLength(self, nums: List[int]) -> int:
preC,curC,res = 0,0,1 #题目里nums长度大于等于1当长度为1时其实到不了for循环里去所以不用考虑nums长度
if len(nums) <= 1:
return len(nums) # 如果数组长度为0或1则返回数组长度
preDiff,curDiff ,result = 0,0,1 #题目里nums长度大于等于1当长度为1时其实到不了for循环里去所以不用考虑nums长度
for i in range(len(nums) - 1):
curC = nums[i + 1] - nums[i]
if curC * preC <= 0 and curC !=0: #差值为0时不算摆动
res += 1
preC = curC #如果当前差值和上一个差值为一正一负时,才需要用当前差值替代上一个差值
return res
curDiff = nums[i + 1] - nums[i]
if curDiff * preDiff <= 0 and curDiff !=0: #差值为0时不算摆动
result += 1
preDiff = curDiff #如果当前差值和上一个差值为一正一负时,才需要用当前差值替代上一个差值
return result
```
**动态规划**
动态规划版本一
```python
class Solution:
@ -341,25 +363,44 @@ class Solution:
return max(dp[-1][0], dp[-1][1])
```
动态规划版本二
```python
class Solution:
def wiggleMaxLength(self, nums: List[int]) -> int:
# up i作为波峰最长的序列长度
# down i作为波谷最长的序列长度
n = len(nums)
# 长度为0和1的直接返回长度
if n<2: return n
for i in range(1,n):
if nums[i]>nums[i-1]:
# nums[i] 为波峰1. 前面是波峰up值不变2. 前面是波谷down值加1
# 目前up值取两者的较大值(其实down+1即可可以推理前一步down和up最多相差1所以down+1>=up)
up = max(up, down+1)
elif nums[i]<nums[i-1]:
# nums[i] 为波谷1. 前面是波峰up+12. 前面是波谷down不变取较大值
down = max(down, up+1)
return max(up, down)
def wiggleMaxLength(self, nums):
dp = [[0, 0] for _ in range(len(nums))] # 创建二维dp数组用于记录摆动序列的最大长度
dp[0][0] = dp[0][1] = 1 # 初始条件序列中的第一个元素默认为峰值最小长度为1
for i in range(1, len(nums)):
dp[i][0] = dp[i][1] = 1 # 初始化当前位置的dp值为1
for j in range(i):
if nums[j] > nums[i]:
dp[i][1] = max(dp[i][1], dp[j][0] + 1) # 如果前一个数比当前数大可以形成一个上升峰值更新dp[i][1]
for j in range(i):
if nums[j] < nums[i]:
dp[i][0] = max(dp[i][0], dp[j][1] + 1) # 如果前一个数比当前数小可以形成一个下降峰值更新dp[i][0]
return max(dp[-1][0], dp[-1][1]) # 返回最大的摆动序列长度
```
动态规划版本三优化
```python
class Solution:
def wiggleMaxLength(self, nums):
if len(nums) <= 1:
return len(nums) # 如果数组长度为0或1则返回数组长度
up = down = 1 # 记录上升和下降摆动序列的最大长度
for i in range(1, len(nums)):
if nums[i] > nums[i-1]:
up = down + 1 # 如果当前数比前一个数大,则可以形成一个上升峰值
elif nums[i] < nums[i-1]:
down = up + 1 # 如果当前数比前一个数小,则可以形成一个下降峰值
return max(up, down) # 返回上升和下降摆动序列的最大长度
```
### Go
**贪心**

View File

@ -177,32 +177,33 @@ class Solution {
```
### Python
贪心 大饼干优先
```python
class Solution:
# 思路1优先考虑小胃口
def findContentChildren(self, g: List[int], s: List[int]) -> int:
g.sort()
s.sort()
res = 0
for i in range(len(s)):
if res <len(g) and s[i] >= g[res]: #小饼干先喂饱小胃口
res += 1
return res
def findContentChildren(self, g, s):
g.sort() # 将孩子的贪心因子排序
s.sort() # 将饼干的尺寸排序
index = len(s) - 1 # 饼干数组的下标,从最后一个饼干开始
result = 0 # 满足孩子的数量
for i in range(len(g)-1, -1, -1): # 遍历胃口,从最后一个孩子开始
if index >= 0 and s[index] >= g[i]: # 遍历饼干
result += 1
index -= 1
return result
```
贪心 小饼干优先
```python
class Solution:
# 思路2优先考虑大胃口
def findContentChildren(self, g: List[int], s: List[int]) -> int:
g.sort()
s.sort()
start, count = len(s) - 1, 0
for index in range(len(g) - 1, -1, -1): # 先喂饱大胃口
if start >= 0 and g[index] <= s[start]:
start -= 1
count += 1
return count
def findContentChildren(self, g, s):
g.sort() # 将孩子的贪心因子排序
s.sort() # 将饼干的尺寸排序
index = 0
for i in range(len(s)): # 遍历饼干
if index < len(g) and g[index] <= s[i]: # 如果当前孩子的贪心因子小于等于当前饼干尺寸
index += 1 # 满足一个孩子,指向下一个孩子
return index # 返回满足的孩子数目
```
### Go

View File

@ -268,80 +268,56 @@ class Solution {
### Python
python3
**回溯**
回溯 利用set去重
```python
class Solution:
def __init__(self):
self.paths = []
self.path = []
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
'''
本题求自增子序列,所以不能改变原数组顺序
'''
self.backtracking(nums, 0)
return self.paths
def backtracking(self, nums: List[int], start_index: int):
# 收集结果同78.子集,仍要置于终止条件之前
if len(self.path) >= 2:
# 本题要求所有的节点
self.paths.append(self.path[:])
def findSubsequences(self, nums):
result = []
path = []
self.backtracking(nums, 0, path, result)
return result
def backtracking(self, nums, startIndex, path, result):
if len(path) > 1:
result.append(path[:]) # 注意要使用切片将当前路径的副本加入结果集
# 注意这里不要加return要取树上的节点
# Base Case可忽略
if start_index == len(nums):
return
# 单层递归逻辑
# 深度遍历中每一层都会有一个全新的usage_list用于记录本层元素是否重复使用
usage_list = set()
# 同层横向遍历
for i in range(start_index, len(nums)):
# 若当前元素值小于前一个时(非递增)或者曾用过,跳入下一循环
if (self.path and nums[i] < self.path[-1]) or nums[i] in usage_list:
uset = set() # 使用集合对本层元素进行去重
for i in range(startIndex, len(nums)):
if (path and nums[i] < path[-1]) or nums[i] in uset:
continue
usage_list.add(nums[i])
self.path.append(nums[i])
self.backtracking(nums, i+1)
self.path.pop()
uset.add(nums[i]) # 记录这个元素在本层用过了,本层后面不能再用了
path.append(nums[i])
self.backtracking(nums, i + 1, path, result)
path.pop()
```
**回溯+哈希表去重**
回溯 利用哈希表去重
```python
class Solution:
def __init__(self):
self.paths = []
self.path = []
def findSubsequences(self, nums):
result = []
path = []
self.backtracking(nums, 0, path, result)
return result
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
'''
本题求自增子序列,所以不能改变原数组顺序
'''
self.backtracking(nums, 0)
return self.paths
def backtracking(self, nums: List[int], start_index: int):
# 收集结果同78.子集,仍要置于终止条件之前
if len(self.path) >= 2:
# 本题要求所有的节点
self.paths.append(self.path[:])
def backtracking(self, nums, startIndex, path, result):
if len(path) > 1:
result.append(path[:]) # 注意要使用切片将当前路径的副本加入结果集
# Base Case可忽略
if start_index == len(nums):
return
used = [0] * 201 # 使用数组来进行去重操作,题目说数值范围[-100, 100]
for i in range(startIndex, len(nums)):
if (path and nums[i] < path[-1]) or used[nums[i] + 100] == 1:
continue # 如果当前元素小于上一个元素,或者已经使用过当前元素,则跳过当前元素
used[nums[i] + 100] = 1 # 标记当前元素已经使用过
path.append(nums[i]) # 将当前元素加入当前递增子序列
self.backtracking(nums, i + 1, path, result)
path.pop()
# 单层递归逻辑
# 深度遍历中每一层都会有一个全新的usage_list用于记录本层元素是否重复使用
usage_list = [False] * 201 # 使用列表去重,题中取值范围[-100, 100]
# 同层横向遍历
for i in range(start_index, len(nums)):
# 若当前元素值小于前一个时(非递增)或者曾用过,跳入下一循环
if (self.path and nums[i] < self.path[-1]) or usage_list[nums[i]+100] == True:
continue
usage_list[nums[i]+100] = True
self.path.append(nums[i])
self.backtracking(nums, i+1)
self.path.pop()
```
### Go

View File

@ -326,7 +326,22 @@ class Solution:
return root
```
递归法(版本四)
```python
class Solution:
def insertIntoBST(self, root, val):
if root is None:
node = TreeNode(val)
return node
if root.val > val:
root.left = self.insertIntoBST(root.left, val)
if root.val < val:
root.right = self.insertIntoBST(root.right, val)
return root
```
迭代法
```python

View File

@ -356,76 +356,80 @@ Python
```python
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
res = []
nums.sort()
def backtracking(start, path):
res.append(path)
uset = set()
for i in range(start, len(nums)):
if nums[i] not in uset:
backtracking(i + 1, path + [nums[i]])
uset.add(nums[i])
def subsetsWithDup(self, nums):
nums.sort() # 去重需要排序
result = []
self.backtracking(nums, 0, [], result)
return result
def backtracking(self, nums, startIndex, path, result):
result.append(path[:])
used = set()
for i in range(startIndex, len(nums)):
if nums[i] in used:
continue
used.add(nums[i])
path.append(nums[i])
self.backtracking(nums, i + 1, path, result)
path.pop()
backtracking(0, [])
return res
```
**40. 组合总和 II**
```python
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
def combinationSum2(self, candidates, target):
candidates.sort()
result = []
self.backtracking(candidates, target, 0, 0, [], result)
return result
def backtracking(start, path):
if sum(path) == target:
res.append(path)
elif sum(path) < target:
used = set()
for i in range(start, len(candidates)):
if candidates[i] in used:
continue
else:
used.add(candidates[i])
backtracking(i + 1, path + [candidates[i]])
backtracking(0, [])
def backtracking(self, candidates, target, sum, startIndex, path, result):
if sum == target:
result.append(path[:])
return
used = set()
for i in range(startIndex, len(candidates)):
if sum + candidates[i] > target:
break
if candidates[i] in used:
continue
used.add(candidates[i])
sum += candidates[i]
path.append(candidates[i])
self.backtracking(candidates, target, sum, i + 1, path, result)
sum -= candidates[i]
path.pop()
return res
```
**47. 全排列 II**
```python
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
path = []
res = []
used = [False]*len(nums)
def permuteUnique(self, nums):
nums.sort() # 排序
result = []
self.backtracking(nums, [False] * len(nums), [], result)
return result
def backtracking():
if len(path) == len(nums):
res.append(path.copy())
deduplicate = set()
for i, num in enumerate(nums):
if used[i] == True:
continue
if num in deduplicate:
continue
def backtracking(self, nums, used, path, result):
if len(path) == len(nums):
result.append(path[:])
return
used_set = set()
for i in range(len(nums)):
if nums[i] in used_set:
continue
if not used[i]:
used_set.add(nums[i])
used[i] = True
path.append(nums[i])
backtracking()
used[i] = False
self.backtracking(nums, used, path, result)
path.pop()
deduplicate.add(num)
backtracking()
used[i] = False
return res
```
JavaScript