代码随想录 -- 回溯 -- 组合

知识点

回溯算法基础讲解:代码随想录 (programmercarl.com)

回溯算法模板:

void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

 题目

77. 组合 - 力扣(LeetCode)

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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值