一、93.复原IP地址
题目链接:93. 复原 IP 地址 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——93.复原IP地址
视频讲解:回溯算法如何分割字符串并判断是合法IP?| LeetCode:93.复原IP地址_哔哩哔哩_bilibili
切割问题,并判断合法性。
树形结构:
class Solution:
# 1. 确定递归函数的参数和返回值
# pointsum,记录 "." 数量
# current,记录当前构建ip地址的前缀部分
def backtracking(self, result, s, startindex, pointsum, current):
# 2. 确定递归终止条件
if pointsum == 3:
# 判断最后一段合法性
if self.is_valid(s, startindex, len(s) - 1):
# 添加最后一段字符串
current += s[startindex:]
result.append(current)
return
# 3. 确定单层递归逻辑
for i in range(startindex, len(s)):
# 判断切割字串[startindex, i]之间字符串的合法性
if self.is_valid(s, startindex, i):
sub = s[startindex:i + 1]
pointsum += 1
self.backtracking(result, s, i + 1, pointsum, current + sub + ".")
pointsum -= 1 # 回溯
# 判断合法性函数
def is_valid(self, s, start, end):
# 起始位置大于终止位置
if start > end:
return False
# 含有前导0错
if s[start] == '0' and start != end:
return False
num = 0
for i in range(start, end + 1):
# 遇到非数字不合法
if not s[i].isdigit():
return False
# 大于255不合法
num = num * 10 + int(s[i])
if num > 255:
return False
return True
def restoreIpAddresses(self, s: str) -> List[str]:
result = []
self.backtracking(result, s, 0, 0, "")
return result
二、78.子集
题目链接:78. 子集 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——78.子集
视频讲解:回溯算法解决子集问题,树上节点都是目标集和! | LeetCode:78.子集_哔哩哔哩_bilibili
思路:所有叶子节点集合,每一层递归都要收集结果放进结果集。
class Solution:
#1. 确定递归函数的参数和返回值
def backtracking(self, nums, path, result, startindex):
# 收获结果的逻辑要放在终止条件之前,如果放在下面会给最后一个元素的结果省略掉
result.append(path[:])
## 2. 确定递归终止条件,终止条件可以省略
# if startindex >= len(nums):
# return
# 3. 确定单层递归逻辑
for i in range(startindex, len(nums)):
path.append(nums[i])
self.backtracking(nums, path, result, i + 1)
path.pop()
def subsets(self, nums: List[int]) -> List[List[int]]:
path = []
result = []
self.backtracking(nums, path, result, 0)
return result
三、90.子集II
题目链接:90. 子集 II - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——90.子集II
视频讲解:回溯算法解决子集问题,如何去重?| LeetCode:90.子集II_哔哩哔哩_bilibili
Note:为40. 组合总和II 和 78.子集知识点的结合。
class Solution:
# 1. 确定递归函数的参数和返回值
def backtracking(self, nums, path, result, startindex, used):
# 2. 确定递归终止条件
result.append(path[:])
# 3. 确定单层递归逻辑
for i in range(startindex, len(nums)):
# 去重,如果当前元素与前一个元素相同且前一个元素没用过
if i > startindex and nums[i] == nums[i - 1] and used[i - 1] == False:
continue
path.append(nums[i])
used[i] = True
self.backtracking(nums, path, result, i + 1, used)
path.pop() # 回溯
used[i] = False # 回溯
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
used = [False] * len(nums)
path = []
result = []
nums.sort() # 排序
self.backtracking(nums, path, result, 0, used)
return result