知识点
回溯算法基础讲解:代码随想录 (programmercarl.com)
回溯算法模板:
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
题目
class Solution(object):
def back(self,n,k,startIndex):
if len(self.path)==k:
subPath=self.path[:]
self.result.append(subPath)
return
for i in range(startIndex,n+1):
self.path.append(i)
self.back(n,k,i+1)
self.path.pop()
def combine(self, n, k):
self.result=[]
self.path=[]
self.back(n,k,1)
return self.result
错误
一开始的代码一直返回空列表:
class Solution(object):
def back(self,n,k,startIndex):
if len(self.path)==k:
self.result.append(path) // 问题所在
return
for i in range(startIndex,n+1):
self.path.append(i)
self.back(n,k,i+1)
self.path.pop()
def combine(self, n, k):
self.result=[]
self.path=[]
self.back(n,k,1)
return self.result
原因:将 self.path
直接添加到 self.result
中。由于 self.path
是一个列表,它是可变的,并且在递归过程中会被修改。这意味着 self.result
中的所有条目最终都将指向同一个列表,该列表在递归结束时将是空的,因为 path.pop()
会被调用。
解决方法:为了解决这个问题,应该在将 self.path
添加到 self.result
之前,建 self.path
的一个副本。添加了 self.path[:]
来创建列表的副本,这样 self.result
中的每个条目都将是一个独立的列表,不会因为 self.path
的后续修改而受到影响。
剪枝优化
class Solution(object):
def back(self,n,k,startIndex):
if len(self.path)==k:
subPath=self.path[:]
self.result.append(subPath)
return
for i in range(startIndex,n-(k-len(self.path))+2): // 优化在这里
self.path.append(i)
self.back(n,k,i+1)
self.path.pop()
def combine(self, n, k):
self.result=[]
self.path=[]
self.back(n,k,1)
return self.result
因为要求k个元素,假设目前path中已经有x个元素了,那么就还要k-x个元素,为了保证startIndex到循环结尾能有k-x个元素,所以循环的结束应该是n-(k-x)+1,Python中不包含结尾,所以是+2.