python
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
n = len(s)
res = []
path = []
def backtrack(startIndx : int) -> None:
if startIndx == n and len(path) == 4:
res.append(".".join(path))
return
remain_char = len(s) - startIndx
remain_seg = 4 - len(path)
if remain_char > 3 * remain_seg or remain_char < remain_seg :
# 剪枝:如果剩余的字符串太多或太少,直接返回
return
for i in range(startIndx, min(startIndx + 3, len(s))):
# 每个被分割的字串都在3或者字符串长度结尾以内
subStr = s[startIndx:i + 1]
if len(subStr) > 1 and subStr[0] == '0':
# 不能有前导零
break
if int(subStr) > 255:
# 数值不大于255
break
path.append(subStr)
backtrack(i + 1)
path.pop()
backtrack(0)
return res
这里用回溯和dp都能做,在实际算法中,回溯更偏向于搜索所有路径,dp更偏向于找出最优解
回溯
python
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
# 决策树,每次都可以选择拿或不拿当前元素
ans = []
path = []
n = len(nums)
def backtrack(startIdx:int) -> None:
ans.append(path[:])
for i in range(startIdx, n):
# 将当前元素放进子集中,代表选择当前元素
path.append(nums[i])
# 并进行下一次迭代,从剩余的列表中找出包含当前nums[i]的元素
backtrack(i + 1)
# 弹出当前元素,代表不选,下一次循环接着从下一个元素开始选
path.pop()
backtrack(0)
return ans
dp
python
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
dp = [[]]
for num in nums:
new_subsets = []
for cur in dp:
new_subsets.append(cur + [num])
dp.extend(new_subsets)
return dp
https://qcn7yki7og1q.feishu.cn/record/OWgEretm4eHCFec2E8GcYxrPnv9
杀死同一树层的判断逻辑
if i > startIdx and nums[i] == nums[i - 1]
python
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
ans = []
path = []
n = len(nums)
nums.sort()
def backstrack(startIdx:int) -> None:
ans.append(path[:])
for i in range(startIdx, n):
if i > startIdx and nums[i] == nums[i - 1]:
continue
path.append(nums[i])
backstrack(i + 1)
path.pop()
backstrack(0)
return ans