基于Python数据结构之递归与回溯搜索


Posted in Python onFebruary 26, 2020

目录

1. 递归函数与回溯深搜的基础知识

2. 求子集 (LeetCode 78)

3. 求子集2 (LeetCode 90)

4. 组合数之和(LeetCode 39,40)

5. 生成括号(LeetCode 22)

6. N皇后(LeetCode 51,52)

7. 火柴棍摆正方形(LeetCode 473)

1. 递归函数与回溯深搜的基础知识

递归是指在函数内部调用自身本身的方法。能采用递归描述的算法通常有这样的特征:为求解规模为N的问题,设法将它分解成规模较小的问题,然后从这些小问题的解方便地构造出大问题的解,并且这些规模较小的问题也能采用同样的分解和综合方法,分解成规模更小的问题,并从这些更小问题的解构造出规模较大问题的解。特别地,当规模N=1时,能直接得解。

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

2. 求子集 (LeetCode 78 Subsets)

2.1题目

Given a set of distinct integers, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.

For example,
If nums = [1,2,3], a solution is:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]

2.2思路

初始化,[ ]的子集为[ [ ] ]

nums[ : n]的子集为所有nums[ : n-1]的子集 加上所有nums[ : n-1]的子集+元素nums[n-1]

2.3代码

class Solution(object):
 def subsets(self, nums):
  """
  :type nums: List[int]
  :rtype: List[List[int]]
  """
  size = len(nums)
  return self.solve(nums, size)
 def solve(self, nums, n):
  if n == 0:
   return [[]]
  temp = self.solve(nums[:n-1], n-1)
  ans = temp[:]
  for i in temp:
   ans.append(i + [nums[n-1]])
  return ans

3. 求子集2 (LeetCode 90 Subsets II)

3.1题目

Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.

For example,
If nums = [1,2,2], a solution is:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]

3.2思路

在上一题思路的基础上,当nums[i]=nums[i-1]时,添加子集时只需在上一步增加的子集基础上进行添加nums[i],而不需要对所有子集进行添加nums[i]。故在递归返回结果时,返回两个结果,一个是所有子集,还有一个是该步骤中添加的子集的集合。

3.3代码

class Solution(object):
 def subsetsWithDup(self, nums):
  """
  :type nums: List[int]
  :rtype: List[List[int]]
  """
  nums.sort()
  size = len(nums)
  return self.solve(nums, size)[0]


 def solve(self, nums, n):
  if n == 0:
   return [[]],[[]]
  if n == 1:
   return [[],[nums[n-1]]],[[nums[n-1]]]
  temp = self.solve(nums[:n-1], n-1)  
  ans = temp[0][:]
  l = len(ans)
  if nums[n-1] == nums[n-2]:
   for i in temp[1]:
    ans.append(i + [nums[n-1]])
  else:
   for i in temp[0]:
    ans.append(i + [nums[n-1]])
  return ans,ans[l:]

4. 组合数之和(LeetCode 39,40 )

4.1题目

LeetCode 39 Combination Sum

Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
The same repeated number may be chosen from C unlimited number of times.
Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
For example, given candidate set [2, 3, 6, 7] and target 7,
A solution set is:
[
[7],
[2, 2, 3]
]

LeetCode 40 Combination Sum II

Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
Each number in C may only be used once in the combination.
Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8,
A solution set is:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]

4.2思路

LeetCode 39 Combination Sum

(1)对给定的数字集合进行排序

(2)target=T,从数组中找一个数n,target= T-n,如果target= 0,则寻找成功添加结果,如果taget比候选数字中的最小值还小,则寻找失败,不添加

(3)注意:按从小到大的顺序进行查找,如果某数已找到,则在找下一个时,不包括该数

LeetCode 40 Combination Sum II

该题与上一题相比,区别在于,给定的集合列表中数字可能重复,目标集合中的数字只能使用给定集合中的数字,并且每个数字只能使用一次。注意,由于存在重复的数字,故需要保证结果中的路径集合没有重复。所以当出现candidates[i]==candidates[i-1],跳过。

4.3代码

LeetCode 39 Combination Sum

class Solution(object):
 def combinationSum(self, candidates, target):
  """
  :type candidates: List[int]
  :type target: int
  :rtype: List[List[int]]
  """
  candidates.sort()
  self.ans = []
  self.solve(candidates, target, 0 ,[])
  return self.ans

 def solve(self, candidates, target, start, path):
  if target == 0:
   self.ans.append(path)
   return 
  if target < 0:
   return
  size = len(candidates)
  for i in range(start, size):
   if candidates[i] > target:
    return 
   self.solve(candidates, target - candidates[i], i, path + [candidates[i]])

LeetCode 40 Combination Sum II

class Solution(object):
 def combinationSum2(self, candidates, target):
  """
  :type candidates: List[int]
  :type target: int
  :rtype: List[List[int]]
  """
  candidates.sort()
  self.ans = []
  self.solve(candidates, target, 0, [])
  return self.ans

 def solve(self, candidates, target, start, path):
  if target == 0:
   self.ans.append(path)
   return
  if target < 0:
   return 
  size = len(candidates)
  for i in range(start, size):
   if i != start and candidates[i] == candidates[i-1]:
    continue
   self.solve(candidates, target - candidates[i], i + 1, path + [candidates[i]])

5. 生成括号(LeetCode 22 Generate Parentheses)

5.1题目

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
For example, given n = 3, a solution set is:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]

5.2思路

在任意位置,左括号的个数要大于等于右括号的个数,如果左括号的个数有剩余,则+'(‘,递归,如果右括号有剩余,且小于左括号的的个数,则 +‘)‘,最后左右括号都不剩则排列结束。

5.3代码

class Solution(object):
 def generateParenthesis(self, n):
  """
  :type n: int
  :rtype: List[str]
  """
  self.res = []
  self.generateParenthesisIter('',n, n)
  return self.res

 def generateParenthesisIter(self, mstr, r, l):
  if r == 0 and l ==0:
   self.res.append(mstr)
  if l > 0:
   self.generateParenthesisIter(mstr+'(', r, l-1)
  if r > 0 and r > l:
   self.generateParenthesisIter(mstr+')', r-1, l)

6. N皇后(LeetCode 51 ,52)

6.1题目

LeetCode 51 N-Queens

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.
Given an integer n, return all distinct solutions to the n-queens puzzle.
Each solution contains a distinct board configuration of the n-queens' placement, where ‘Q' and ‘.' both indicate a queen and an empty space respectively.
For example,
There exist two distinct solutions to the 4-queens puzzle:
[
[“.Q..”, // Solution 1
“…Q”,
“Q…”,
“..Q.”],

[“..Q.”, // Solution 2
“Q…”,
“…Q”,
“.Q..”]
]

LeetCode 52 N-Queens II

Follow up for N-Queens problem.
Now, instead outputting board configurations, return the total number of distinct solutions.

6.2思路

LeetCode 51 N-Queens

n*n的板上放置n个皇后,n个皇后不能发生攻击,即行/列/斜没有其他皇后,要求给出所有解决方案。每次在棋盘上的当前位置放置一个皇后,当不与前面行的皇后发生冲突时,则可以递归处理下面行的皇后。因为有n行n列,n个皇后,故每行可以放一个皇后,每一列也只能放置一个皇后。通过检查第k个皇后能否被放置在第j列进行判断(不与其他皇后在同行,同列,同斜行)。使用一个长度为n的列表记录第k行皇后放置的列位置。

LeetCode 52 N-Queens II

和上一题思路一样,返回结果的长度即可

6.3代码

LeetCode 51 N-Queens

class Solution(object):
 def solveNQueens(self, n):
  """
  :type n: int
  :rtype: List[List[str]]
  """
  self.ans = []
  self.board = [-1 for i in range(n)]
  self.dfs(0, [], n)
  return self.ans
 def isQueen(self, krow, jcolumn):
  for i in range(krow):
   if self.board[i] == jcolumn or abs(krow-i) == abs(self.board[i] - jcolumn):
    return False
  return True

 def dfs(self, krow, rowlist, n):
  if krow == n:
   self.ans.append(rowlist)
  for i in range(n):
   if self.isQueen(krow,i):
    self.board[krow] = i
    self.dfs(krow + 1,rowlist + ['.' * i + 'Q' + '.' * (n-i-1)],n)

LeetCode 52 N-Queens II

class Solution(object):
 def totalNQueens(self, n):
  """
  :type n: int
  :rtype: int
  """
  self.ans = []
  self.board = [-1 for i in range(n)]
  self.dfs(0, [], n)
  return len(self.ans)
 def isQueen(self, krow, jcolumn):
  for i in range(krow):
   if self.board[i] == jcolumn or abs(krow-i) == abs(self.board[i] - jcolumn):
    return False
  return True

 def dfs(self, krow, rowlist, n):
  if krow == n:
   self.ans.append(rowlist)
  for i in range(n):
   if self.isQueen(krow,i):
    self.board[krow] = i
    self.dfs(krow + 1,rowlist + ['.' * i + 'Q' + '.' * (n-i-1)],n)

7. 火柴棍摆正方形(LeetCode 473 Matchsticks to Square)

7.1题目

Remember the story of Little Match Girl? By now, you know exactly what matchsticks the little match girl has, please find out a way you can make one square by using up all those matchsticks. You should not break any stick, but you can link them up, and each matchstick must be used exactly one time.

Your input will be several matchsticks the girl has, represented with their stick length. Your output will either be true or false, to represent whether you could make one square using all the matchsticks the little match girl has.

Example 1:
Input: [1,1,2,2,2]
Output: true

Explanation: You can form a square with length 2, one side of the square came two sticks with length 1.
Example 2:
Input: [3,3,3,3,4]
Output: false

Explanation: You cannot find a way to form a square with all the matchsticks.

7.2思路

根据火柴棒的总长度,求正方形的变长,若变长不为整数,则直接判断为False。

先将nums按从大到小的顺序排序,used为和nums等长的列表,用于记录第i位的元素是否被用过。

使用递归判断从第i位元素起始,能否找到这样的组合满足其长度之和等于正方形的边长。

(1)若满足初始条件,则返回结果(True or False)

(2)若不满足条件,则进行递归,在剩下的元素中进行选择,看有没有满足情况的,如果没有满足情况的,used对应位置改为False,结果返回False

(3)对nums中的每个元素进行遍历,看能否满足nums中的每个火柴棒都能找到对应边的组合,其长度和等于正方形边长。

7.3代码

class Solution(object):
 def makesquare(self, nums):
  """
  :type nums: List[int]
  :rtype: bool
  """
  total = sum(nums)
  if total%4 != 0 or len(nums)<4: return False
  size = total/4
  nums.sort(reverse=True)
  used = [False]*len(nums)
  def dfs(i, expect):
   if i >= len(nums): return expect%size == 0
   if used[i]: return dfs(i+1, expect)
   used[i] = True
   if nums[i] == expect: return True
   if nums[i] < expect:
    expect -= nums[i]
    available = [j for j in range(i+1, len(nums)) if not used[j]]
    for x in available:
     if dfs(x, expect): 
      return True
   used[i] = False
   return False
  for i in range(len(nums)):
   if not dfs(i, size): return False
  return True

以上这篇基于Python数据结构之递归与回溯搜索就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python 调用VC++的动态链接库(DLL)
Sep 06 Python
Python写的Discuz7.2版faq.php注入漏洞工具
Aug 06 Python
python实现图像识别功能
Jan 29 Python
Python实现确认字符串是否包含指定字符串的实例
May 02 Python
python实现蒙特卡罗方法教程
Jan 28 Python
Python父目录、子目录的相互调用方法
Feb 16 Python
Python datetime和unix时间戳之间相互转换的讲解
Apr 01 Python
教你一步步利用python实现贪吃蛇游戏
Jun 27 Python
Flask框架学习笔记之模板操作实例详解
Aug 15 Python
Windows下pycharm创建Django 项目(虚拟环境)过程解析
Sep 16 Python
Python paramiko使用方法代码汇总
Nov 20 Python
Python实现文本文件拆分写入到多个文本文件的方法
Apr 18 Python
深度学习入门之Pytorch 数据增强的实现
Feb 26 #Python
Python基于Dlib的人脸识别系统的实现
Feb 26 #Python
python 回溯法模板详解
Feb 26 #Python
python实现信号时域统计特征提取代码
Feb 26 #Python
Python 基于FIR实现Hilbert滤波器求信号包络详解
Feb 26 #Python
python实现逆滤波与维纳滤波示例
Feb 26 #Python
Python全面分析系统的时域特性和频率域特性
Feb 26 #Python
You might like
日本十大最佳动漫,全都是二次元的神级作品
2019/10/05 日漫
解析在apache里面给php写虚拟目录的详细方法
2013/06/24 PHP
typecho插件编写教程(四):插件挂载
2015/05/28 PHP
php usort 使用用户自定义的比较函数对二维数组中的值进行排序
2017/05/02 PHP
简单JS代码压缩器
2006/10/12 Javascript
你真的了解JavaScript吗?
2007/02/24 Javascript
$.getJSON在IE下失效的原因分析及解决方法
2013/06/16 Javascript
使用javascript实现页面定时跳转总结篇
2013/09/21 Javascript
jQuery实现网站添加高亮突出显示效果的方法
2015/06/26 Javascript
JS实现的5级联动Select下拉选择框实例
2015/08/17 Javascript
常常会用到的截取字符串substr()、substring()、slice()方法详解
2015/12/16 Javascript
AngularJS入门教程之链接与图片模板详解
2016/08/19 Javascript
js滚轮事件兼容性问题需要注意哪些
2016/11/15 Javascript
jquery实现刷新随机变化样式特效(tag标签样式)
2017/02/03 Javascript
用node和express连接mysql实现登录注册的实现代码
2017/07/05 Javascript
Vue2 Vue-cli中使用Typescript的配置详解
2017/07/24 Javascript
Vue + Vue-router 同名路由切换数据不更新的方法
2017/11/20 Javascript
原生JS实现简单的无缝自动轮播效果
2018/09/26 Javascript
[01:46]2020完美世界全国高校联赛秋季赛报名开启
2020/10/15 DOTA
python解析xml模块封装代码
2014/02/07 Python
Python中的map()函数和reduce()函数的用法
2015/04/27 Python
在Python中使用poplib模块收取邮件的教程
2015/04/29 Python
Python中新式类与经典类的区别详析
2019/07/10 Python
tensorflow中tf.slice和tf.gather切片函数的使用
2020/01/19 Python
Python while true实现爬虫定时任务
2020/06/08 Python
基于css3仿造window7的开始菜单
2010/06/17 HTML / CSS
结婚保证书范文
2014/04/29 职场文书
计算机软件专业求职信
2014/06/10 职场文书
公务员群众路线专题民主生活会发言材料
2014/09/17 职场文书
领导班子党的群众路线教育实践活动对照检查材料
2014/09/25 职场文书
乡镇遵守党的政治纪律情况对照检查材料
2014/09/26 职场文书
2016春季幼儿园开学寄语
2015/12/03 职场文书
幼师自荐信范文(2016推荐篇)
2016/01/28 职场文书
解决Jupyter-notebook不弹出默认浏览器的问题
2021/03/30 Python
Python实战之实现康威生命游戏
2021/04/26 Python
JavaScript原型链中函数和对象的理解
2022/06/16 Javascript