python 回溯法模板详解


Posted in Python onFebruary 26, 2020

什么是回溯法

回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

无重复元素全排列问题

给定一个所有元素都不同的list,要求返回list元素的全排列。

设n = len(list),那么这个问题可以考虑为n叉树,对这个树进行dfs,这个问题里的回溯点就是深度(也就是templist的长度)为n时,回溯的条件就是当前元素已经出现在templist中了。

回溯法与递归:

回溯法是一种思想,递归是一种形式

class Solution(object):

  #rtlist用来存储所有的返回所有排列,templist用来生成每个排列
  def backtrack(self,rtlist,templist,nums):
    if(len(templist) == len(nums)):
      rtlist.append(templist[:])
    else:
      for i in nums:

        if(i in templist): #如果在当前排列中已经有i了,就continue,相当于分支限界,即不对当前节点子树搜寻了
          continue
        templist.append(i)
        self.backtrack(rtlist,templist,nums)
        templist.pop() #把结尾的元素用nums中的下一个值替换掉,遍历下一颗子树

  def permute(self,nums):
    rtlist = []
    templist = []
    self.backtrack(rtlist,templist,nums)
    return rtlist

nums=[1,2,3]时的树结构:

python 回溯法模板详解

关键的就是确定好分支限界以及回溯点。

这里面有一个问题就是每次递归时把新加入的元素从nums删除在递归可不可以,实际上这样的时间复杂度并不会减少太多,因为对list进行操作还需要一定的时间,而原解法中因为有分支限界所以时间复杂度也不会太差。

有重复元素全排列

这个问题和上面的区别主要在于分支限界的差别,不能在使用出现重复元素作为回溯条件了,否则所有的都不满足。

这里我们应该使用计数器记录nums中每个元素出现的次数,如果当前元素超过次数则返回,但是这里还有一个问题就是可能会出现同样的排列多次,这里的解决办法就是同一层不许出现重复元素,这里有两种解决办法,一种是直接传入distinct的数组,还有一种是使用一个集合记录当前层已使用的元素。

第一种方法:

from collections import Counter

class Solution(object):

  def backtrack(self, rtlist, tmplist, counter, nums, length):
    if len(tmplist) == length:#回溯点
      rtlist.append(tmplist[:])
    else:
      for i in nums:#横向遍历
        if counter[i] == 0:#分支限界
          continue

        counter[i] -= 1
        tmplist.append(i)
        self.backtrack(rtlist, tmplist, counter, nums, length)#纵向遍历
        counter[i] += 1
        tmplist.pop()

  def permuteUnique(self, nums):

    rtlist, tmplist, counter = [], [], Counter(nums)
    length = len(nums)
    self.backtrack(rtlist, tmplist, counter, list(set(nums)), length)

    return rtlist

第二种

from collections import Counter

class Solution(object):

  def backtrack(self, rtlist, tmplist, level, counter, nums):
    if len(tmplist) == len(nums):
      rtlist.append(tmplist[:])
    else:
      for i in nums:
        if i in level or counter[i] == 0:
          continue

        counter[i] -= 1

        tmplist.append(i)
        level.add(i)
        self.backtrack(rtlist, tmplist, set(), counter, nums)

        counter[i] += 1
        tmplist.pop()


  def permuteUnique(self, nums):
    if not nums:
      return []
    rtlist, tmplist, level, counter = [], [], set(), Counter(nums)
    self.backtrack(rtlist, tmplist, level, counter, nums)

    return rtlist

在递归时不能用“=”修改父函数的变量,因为“=”只能改变变量的指向,要修改父函数的变量要直接在内存中修改,例如放入容器中可以直接找到变量内存地址。通常使用container.method()。

例如在上面的程序中如果我们想要在回溯点把counter复原不能使用counter = Counter(nums),而是应该逐个修改counter[key]

总结

回溯法其实就是把原问题考虑成一棵树,我们遍历这棵树在不可能的地方返回,不在遍历这个节点的子树,在满足要求时返回。

所以在回溯法中,关键的就是找出合理的分支限界(重要),和返回条件。

更多请参考

多叉树的遍历方法:

def travel(root):
 遍历root
 for subtree_root in 当前层所有节点:

travel(subtree_root)

在for中对一层的所有节点都执行了travel,又因为对所有节点的所有子树都执行了travel,所以可以完成遍历。

以上这篇python 回溯法模板详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中使用partial改变方法默认参数实例
Apr 28 Python
Python如何import文件夹下的文件(实现方法)
Jan 24 Python
详解Python3操作Mongodb简明易懂教程
May 25 Python
TensorFlow 实战之实现卷积神经网络的实例讲解
Feb 26 Python
django2用iframe标签完成网页内嵌播放b站视频功能
Jun 20 Python
python实现简单flappy bird
Dec 24 Python
Python collections中的双向队列deque简单介绍详解
Nov 04 Python
python读写Excel表格的实例代码(简单实用)
Dec 19 Python
Spring http服务远程调用实现过程解析
Jun 11 Python
Python实现加密的RAR文件解压的方法(密码已知)
Sep 11 Python
Matplotlib配色之Colormap详解
Jan 05 Python
jupyter 添加不同内核的操作
Feb 06 Python
python实现信号时域统计特征提取代码
Feb 26 #Python
Python 基于FIR实现Hilbert滤波器求信号包络详解
Feb 26 #Python
python实现逆滤波与维纳滤波示例
Feb 26 #Python
Python全面分析系统的时域特性和频率域特性
Feb 26 #Python
解决pycharm每次打开项目都需要配置解释器和安装库问题
Feb 26 #Python
Python中os模块功能与用法详解
Feb 26 #Python
Python中sys模块功能与用法实例详解
Feb 26 #Python
You might like
新手配置 PHP 调试环境(IIS+PHP+MYSQL)
2007/01/10 PHP
PHP学习笔记 (1) 环境配置与代码调试
2011/06/19 PHP
Yii2 rbac权限控制之rule教程详解
2016/06/23 PHP
javascript的对话框详解与参数
2007/03/08 Javascript
基于JQuery的多标签实现代码
2012/09/19 Javascript
JavaScript使用Prototype实现面向对象的方法
2015/04/14 Javascript
JS新包管理工具yarn和npm的对比与使用入门
2016/12/09 Javascript
React快速入门教程
2017/01/17 Javascript
JavaScript用200行代码制作打飞机小游戏实例
2017/06/21 Javascript
JS实现页面打印(整体、局部)
2017/08/18 Javascript
jquery tmpl模板(实例讲解)
2017/09/02 jQuery
浅谈vue+webpack项目调试方法步骤
2017/09/11 Javascript
jquery学习笔记之无new构建详解
2017/12/07 jQuery
LayUi使用switch开关,动态的去控制它是否被启用的方法
2019/09/21 Javascript
js实现橱窗展示效果
2020/01/11 Javascript
js实现表单项的全选、反选及删除操作示例
2020/06/05 Javascript
[02:49]DAC2018决赛日TOP5 LGD开启黑暗之门绝杀VP
2018/04/08 DOTA
python中的闭包用法实例详解
2015/05/05 Python
python 转换 Javascript %u 字符串为python unicode的代码
2016/09/06 Python
Django接受前端数据的几种方法总结
2016/11/04 Python
Python基于正则表达式实现检查文件内容的方法【文件检索】
2017/08/30 Python
python学习笔记之列表(list)与元组(tuple)详解
2017/11/23 Python
详解如何利用Cython为Python代码加速
2018/01/27 Python
Python实现对文件进行单词划分并去重排序操作示例
2018/07/10 Python
Python----数据预处理代码实例
2019/03/20 Python
TensorFlow中如何确定张量的形状实例
2020/06/23 Python
编写python代码实现简单抽奖器
2020/10/20 Python
西班牙最大的在线滑板和街头服饰商店:Fillow.net
2019/04/15 全球购物
英国莱斯特松木橡木家具网上商店:Choice Furniture Superstore
2019/07/05 全球购物
DC Shoes荷兰官方网站:美国极限运动品牌
2019/10/22 全球购物
如何安装ruby on rails
2014/02/09 面试题
《赶海》教学反思
2014/04/20 职场文书
2014年管理人员工作总结
2014/12/01 职场文书
实践论读书笔记
2015/06/29 职场文书
民间借贷纠纷起诉书
2015/08/03 职场文书
如何起草一份正确的合伙创业协议书?
2019/07/04 职场文书