回溯算法(一) Python实现

什么是回溯?

回溯采用试错的方法去解决问题,一旦发现当前步骤失败,回溯方法就返回上一个步骤,选择另一种方案继续试错。

例题

蓝桥杯 算法提高 阮小二买彩票 Python

回溯法的特点(判断什么时候应该采用回溯算法)

  • 问题的答案有多个元素
    -(彩票号码的排序方式不止一个)
  • 答案要满足一些约束
    -(本题中没有涉及,因为是全排列,但是例如在利用回溯算法解数独的时,需要考虑)
  • 寻找答案的方式在每一个步骤中是相同的
    -(在每次对号码排序时的条件都是一致的,不和已经出现过的排序方式一样)

例题求解:

本题中的数字有n位,如果采用常规思路,例如给出[1,2,3],那么第一个位置有3种选择,第二个位置有两种选择,第三个位置就只有一种选择了。那好,三层循环搞定!不过缺点也来了:

  • 提前就要想好有几层循环(预先要知道数组长度),有几位就要写几层。
  • 你会发现每层的循环做的事情是重复的,无非是数字不同和数字的数目不同

所以我们要写一个helper()方法,代替重复的循环

 def helper(self,n, solution, rst):

        if len(n) == 0: 
            tmp = ''.join(solution)
            if tmp not in rst:
                rst.append(''.join(solution))
                print(''.join(solution))
            return 

        for i in range(len(n)):
            newSolution = solution + [n[i]] 
            newArray = n[:i] + n[i+1:] 
            self.helper(newArray,newSolution,rst)
            

代码中的参数:

  • n,存储排序的对象的列表,这里假设里面有[1,2,3,4]
  • solution,存储当前排列组合的列表,当排序完成时会被输出,建议实际操作并print一下它
  • rst,存储已经出现过的排序方式的列表,用于判定是否重复
    -(因为题中提供的n位数字各位置上的数字可能有重复,同时题目中要求不能输出一样的排序方式)

helper()执行功能的过程:

(1)循环,这个地方建议等把下面的代码执行过程看完再结合思考

for i in range(len(n)):
			# 把n[i]数字加入新的排序输出列表
            newSolution = solution + [n[i]] 
            # 在排下一位置前,创建新的排序对象列表,把n[i]数字去除掉,他现在已经被选择到
            newArray = n[:i] + n[i+1:] 

(2)寻找下一个需要放置的数字

			self.helper(newArray,newSolution,rst)

(3)递归一层一层的进行,那么终止条件是什么呢?就是n中的数字都被选出来排序了

return返回上一步骤,你会发现返回到了上一个helper()的循环函数中

仔细推演,它已经到了最后一个位置上的数字的选择,最后一个位置上只有一种选择

所以helper()会再次返回上一个,即倒数第二个位置上的数字的选择,这里的for循环会把剩余的倒数第二个位置的数字可能有的选择选择完,然后返回到倒数第三个位置,依此类推,一直到最初的第一位置的数字选择。

		# 发现排序对象列表已经选完,输出当前的排序
        if len(n) == 0: 
            tmp = ''.join(solution)
            if tmp not in rst:
                rst.append(''.join(solution))
                print(''.join(solution))
               
                return 
                

完整代码:

class solution:
    rst = []
    solution =[]

    def solvePermutation(self, n):
        self.helper(n, [],[]) # 首次调用

    def helper(self,n, solution, rst):

        if len(n) == 0: # 发现排序对象列表已经选完,输出当前的排序
            tmp = ''.join(solution)
            if tmp not in rst:
                rst.append(''.join(solution))
                print(''.join(solution))
            return # 返回上一步骤,你会发现返回到了上一个helper()的循环函数中,并且会循环下一个n[i],被加入到新的排序,新的n[i]会被去掉

        for i in range(len(n)):
            newSolution = solution + [n[i]] # 把n[i]加入新的排序输出列表
            newArray = n[:i] + n[i+1:] # 创建新的“n”,在排下一位置前,把n[i]去除掉
            self.helper(newArray,newSolution,rst)  # 寻找剩余的下一位置可能的数字

if __name__ == '__main__':
    n = sorted(list(input())) # 排序一遍,以符合题目要求
    solution().solvePermutation(n)


你可能感兴趣的:(算法练习)