93. 复原 IP 地址
回溯
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
res = []
path = []
def _backtracking(start_index, s):
nonlocal path
nonlocal res
if len(path) == 4 and self.is_valid_ip(path):
ip = '.'.join(path)
if len(ip) == len(s) + 3:
res.append(ip)
return
for i in range(start_index, min(len(s), start_index + 3)):
sub = s[start_index : i+1]
path.append(sub)
_backtracking(i+1, s)
path.pop()
_backtracking(0, s)
return res
def is_valid_ip(self, s_list):
for num in s_list:
if len(num) > 1 and num[0] == '0':
return False
if int(num) > 255 or int(num) < 0:
return False
return True
回溯+剪枝
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
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[:])
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
78. 子集
回溯
-
但是要清楚子集问题和组合问题、分割问题的的区别,子集是收集树形结构中树的所有节点的结果。
而组合问题、分割问题是收集树形结构中叶子节点的结果。
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
res = []
path = []
def _backtracking(start_index, nums):
nonlocal path
nonlocal res
# 所有节点的结果
res.append(path[:])
if start_index >= len(nums):
return
for i in range(start_index,len(nums)):
path.append(nums[i])
_backtracking(i+1, nums)
path.pop()
_backtracking(0, nums)
return res
90. 子集 II
回溯+剪枝
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
res = []
path = []
# sorting to remove duplicate
nums.sort()
def _backtracking(start_index, nums):
nonlocal path
nonlocal res
# 所有节点的结果
res.append(path[:])
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
path.append(nums[i])
_backtracking(i+1, nums)
path.pop()
_backtracking(0, nums)
return res