Day 28 回溯算法4
93.复原IP地址
思路
跟上一题分割回文子串类似,用startIndex表示分割线
但是四个整数不知道怎么表示,且不能有前导0也不知道怎么判断
根据代码随想录
要点:
- 定义pointSum,记录分割的逗点的个数
- 终止条件,如果pointSum == 3,且对最后一段进行合法性判断
- for循环中处理逻辑,先对当前段进行合法性判断,当前段由startIndex和i决定
- 不用path单独记录,直接往原来的s字符串中加"."(对于python不适用)
尝试写代码:
class Solution:
def __init__(self):
self.ip = ''
self.result = []
def restoreIpAddresses(self, s: str) -> List[str]:
self.backtracking(s, 0, 0)
return self.result
def isvalid(self, s, start, end):
if len(s[start:end + 1]) > 1 and s[start] == 0:
return False
if int(s[start:end + 1]) > 255:
return False
return True
def backtracking(self, s, startIndex, pointSum):
if pointSum == 3:
if self.isvalid(s, startIndex, len(s) - 1):
self.ip += s[startIndex:len(s) + 1]
self.result.append(self.ip[:])
return
for i in range(startIndex, len(s)):
if self.isvalid(s, startIndex, i):
self.ip = self.ip + s[startIndex:i + 1] + '.'
pointSum += 1
self.backtracking(s, i + 1, pointSum)
self.ip = self.ip[:-(len(s[startIndex:i + 1]) + 2)]
pointSum -= 1
else:
break
最终代码:
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
result = []
self.backtracking(s, 0, 0, "", result)
return result
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)):
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方法
添加字符:.joint
方法
.join()方法中传递的参数需要是可迭代的
插入字符串:
首先将字符串转换为列表,然后使用列表的.insert()
方法来插入字符。
L.insert(index, object) -- insert object before index
78.子集
思路
画树形图,题目中规中矩,在主函数开头先把空列表加入最后的result。
每次更新path时,都把此时的path放入result
尝试写代码:
class Solution:
def __init__(self):
self.path = []
self.result = []
def subsets(self, nums: List[int]) -> List[List[int]]:
self.result.append([])
self.backtracking(nums, 0)
return self.result
def backtracking(self, nums, startIndex):
if startIndex == len(nums):
return
for i in range(startIndex, len(nums)):
self.path.append(nums[i])
self.result.append(self.path[:])
self.backtracking(nums, i + 1)
self.path.pop()
成功通过!
根据代码随想录
如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!
90.子集II
思路
相比于上一题,由于数组中有重复元素,因此需要去重
去重的逻辑,可以先排序,然后判断i + 1是否与i相等
尝试写代码:i > startIndex方法
class Solution:
def __init__(self):
self.path = []
self.result = []
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
nums.sort()
self.backtracking(nums, 0)
return self.result
def backtracking(self, nums, startIndex):
self.result.append(self.path[:])
if startIndex == len(nums):
return
for i in range(startIndex, len(nums)):
if i > startIndex and nums[i - 1] == nums[i]:
continue
self.path.append(nums[i])
self.backtracking(nums, i + 1)
self.path.pop()
used方法:
class Solution:
def __init__(self):
self.path = []
self.result = []
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
used = [False] * len(nums)
nums.sort()
self.backtracking(nums, 0, used)
return self.result
def backtracking(self, nums, startIndex, used):
self.result.append(self.path[:])
if startIndex == len(nums):
return
for i in range(startIndex, len(nums)):
if i > 0 and nums[i - 1] == nums[i] and not used[i - 1]:
continue
self.path.append(nums[i])
used[i] = True
self.backtracking(nums, i + 1, used)
self.path.pop()
used[i] = False