举个例子:["aabac"]
可以分割为以下三种:
["a","a","b","a","c"] ["a","aba","c"] ["aa","b","a","c"]
画图理解:(mermaid画的图有些线的位置比较奇怪,看仔细一点)
绿色框内为找到的分割方案,找到后返回.
灰色框表示非回文串,遇到不是回文串的情况,不再继续向下遍历.
for循环横向遍历,递归纵向遍历.
横向遍历遇到不是回文串的情况,则直接跳到下一个(for循环内需要先判断回文串,再进行递归).
判断是否回文串时,可以用双指针法,也可以直接判断s[start_index: i + 1]
(正序)和s[start_index: i + 1][::-1]
(逆序)是否相等.
class Solution:
def isPalindrome(self, s, start, end): # 判断是否回文
i, j = start, end
while i < j:
if s[i] != s[j]:
return False
i += 1
j -= 1
return True
def backtracking(self, s, startIndex, result, path):
# 切割位置与s长度相同时,找到一组分割方案
if startIndex == len(s):
result.append(path[:])
return
# 单层递归逻辑
# 每次切割的位置(startIndex)要向后移一个
for i in range(startIndex, len(s)):
if self.isPalindrome(s, startIndex, i):
path.append(s[startIndex:i + 1])
self.backtracking(s, i + 1, result, path) # 递归
path.pop() # 回溯
def partition(self, s: str) -> List[List[str]]:
result = []
self.backtracking(s, 0, result, [])
return result
举例:s = "10312"
输出:["1.0.3.12","1.0.31.2","10.3.1.2"]
.
分割为四段,因此.
的数量等于3时,则结束递归if s[start] == '0' and start != end: return False
if not s[i].isdigit(): return False
if num > 255: return False
if len(s) < 4 or len(s) > 12: return []
class Solution:
def isOK(self, s, start, end):
if start > end:
return False
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
num = num * 10 + int(s[i])
if num > 255:
return False
return True
def backtracking(self, s, startIndex, pointNum, current, result):
if pointNum == 3:
if self.isOK(s, startIndex, len(s) - 1):
current += s[startIndex:]
result.append(current)
return
# 单层递归逻辑
# 每次切割的位置向后移一个
for i in range(startIndex, len(s)):
if self.isOK(s, startIndex, i):
sub = s[startIndex:i + 1]
self.backtracking(s, i + 1, pointNum + 1, current + sub + '.', result)
else:
break
def restoreIpAddresses(self, s: str) -> List[str]:
if len(s) < 4 or len(s) > 12: # 直接排除掉不可能构成有效IP的情况
return []
result = []
self.backtracking(s, 0, 0, "", result)
return result
上面那种写法我能理解,但是和我自己的思路还是不太一样。
下面这种写法就比较符合我的思路。
str.join(item)
:str
表示字符串(字符),item
表示一个成员(注意括号里必须只能有一个成员)
该函数的作用是:将item
中的每个成员用str
分隔开,再拼成一个完整的字符串。
所以直接result.append(".".join(path))
就可以实现用.
分隔四个整数的功能了
class Solution:
def isOK(self, s, start, end):
if start > end:
return False
if s[start] == '0' and start != end:
return False
if 0 <= int(s[start:end+1]) <= 255:
return True
def backtracking(self, s, startIndex, path, result):
if startIndex == len(s) and len(path) == 4:
result.append(".".join(path))
return
# 单层递归逻辑
# 每次切割的位置向后移一个
for i in range(startIndex, len(s)):
if self.isOK(s, startIndex, i):
path.append(s[startIndex:i + 1])
self.backtracking(s, i + 1, path, result)
path.pop()
def restoreIpAddresses(self, s: str) -> List[str]:
if len(s) < 4 or len(s) > 12:
return []
result = []
self.backtracking(s, 0, [], result)
return result
总的来说,这道题思路还算好想,但是代码不是很好写。
要注意的点很多,我在自己想的时候就漏掉了段位里有非正整数字符不合法的情况。
举例:nums = [1,2,3,4]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3],[4],[1,4],[2,4],[3,4],[1,2,4],[1,3,4],[2,3,4],[1,2,3,4]]
这道题result
中子集的数量一定是2(len(nums))
每个result
中都有[]
这一子集
本题是找树的所有节点!
第一次传入的path
就是[]
,直接就被result.append(path[:])
了,所以不用担心漏掉[]
class Solution:
def backtracking(self, nums, startIndex, result, path):
result.append(path[:])
if startIndex >= len(nums):
return
for i in range(startIndex, len(nums)):
path.append(nums[i])
self.backtracking(nums, i + 1, result, path)
path.pop()
def subsets(self, nums: List[int]) -> List[List[int]]:
result = []
self.backtracking(nums, 0, result, [])
return result
本题无需考虑顺序问题,因为不管什么顺序都会全都遍历到,比如:nums = [3,1,2]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列
我觉得,对上一题加个判断条件就OK了
class Solution:
def backtracking(self, nums, startIndex, result, path):
result.append(path[:])
if startIndex >= len(nums):
return
for i in range(startIndex, len(nums)):
# 对同一树层使用过的元素进行跳过
if nums[i - 1] == nums[i] and i > startIndex:
continue
path.append(nums[i])
self.backtracking(nums, i + 1, result, path)
path.pop()
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
result = []
path = []
nums.sort()
self.backtracking(nums, 0, result, path)
return result
今天的最后一道题,明明不难,但是由于傻乎乎的复制了上一题的代码改了改就提交了,错了好几次,最后才注意到两道题函数名不一样。。。