回溯问题Python框架总结——排列组合问题

本文是对 leetcode 回溯题的一些模板进行整理总结,很多关于回溯的 blog 都会引用对回溯算法的 official definition 和通用的解题步骤,如果是真的想研究这一算法思想,按照这样的方式来完全没有问题。不过个人觉得如果仅仅只是为了应试,那么掌握一些解题的模板会更直接的帮助理解回溯的算法思想。本文将举一些简单的例子来说明这些模板,不采用树来描述,使得对于数据结构不太了解的读者也相对友好。

基本思想:

回溯问题是对多叉树的深度搜索,遇到不满足条件的节点则回退,递归的搜索答案。在递归调用前,尝试一种可能的方案,那么在递归调用的时候,函数的开始,有判断语句,如果这种方案可行,记录下这种方案,并且 return,否则,继续进行尝试,找到满足条件的解以后,回退到之前的选择。

常见模板:

1、无重复元素的全排列问题(或者有重复元素但是不需要去重)

一般在回溯的过程中,不断缩小原来数组的范围并添加至 t r a c k track track 中,直至枚举完所有的元素,满足条件的添加到 r e s u l t result result 数组中, 模板如下

def problem(nums):
	res = []
	def backtrack(nums, track):
		if (判断满足题目所给的条件):  # 如果不限制每个结果都需要用到所有元素,就不需要 if 判断,直接加入 res
			res.append(track[:])   # 这里必须传入track的拷贝,track[:], 否则答案全是空
			return
		for i in range(len(nums)):
			backtrack(nums[:i] + nums[i+1:], track + nums[i])
		backtrack(nums, [])
	return 题目需要的res相关的参数,输出本身,长度,或者其他的

以下题目为实战中套用框架解题

Leetcode 46 全排列

由于是全排列,只要没得选了,那就是我们所需的答案,加入 r e s u l t result result 并且 r e t u r n return return

class Solution:
	def permute(self, nums: List[int]) -> List[List[int]]:
		res = []
		def backtrack(nums, track):
			if not nums:
				res.append(track[:])
				return
			for i in range(len(nums)):
				backtrack(nums[:i] + nums[i+1:], track + [nums[i]])
		backtrack(nums, [])
		return res
2、有重复元素的全排列问题

遇到有重复元素的问题,最好先进行排序,再采用剪枝的方法来进行去重,具体分析见 4。这里给出全排列有重复元素去重的框架:

def problem(nums):
	res = []
	nums.sort()
	def backtrack(nums, track):
		if (判断满足题目所给的条件):  # 如果不限制每个结果都需要用到所有元素,就不需要 if 判断,直接加入 res
			res.append(track[:])   # 这里必须传入track的拷贝,track[:], 否则答案全是空
			return
		for i in range(len(nums)):
			if i > 0 and nums[i] == nums[i-1]:  #剪枝去重
				continue
			backtrack(nums[:i] + nums[i+1:], track + nums[i])
	backtrack(nums, [])
	return 题目需要的res相关的参数,输出本身,长度,或者其他的

Leetcode 1079 活字印刷

先将字符串放在入列表中进行排序,后进行剪枝去重。

由于不需要求具体有哪些排列,因此只需要用一个变量来记录过程中的结果。类似的, N N N皇后与 N N N皇后Ⅱ 的差别也仅在于是否需要建立一个列表或者一个变量来保存结果。

初始 a n s ans ans 设为 -1,因为题目要求最后的结果非空,提前减去一个空字符串。

class Solution:
	def numTilePossibilities(self, tiles: str) -> int:
		self.ans = -1
		tiles = list(tiles)
		tiles.sort()</
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值