第77期-基础算法:回溯 全排列
1 问题描述
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入: nums = [1,2,3]
输出: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入: nums = [0,1]
输出: [[0,1],[1,0]]
示例 3:
输入: nums = [1]
输出: [[1]]
初始代码
from typing import List class Solution: def combine(self, n: int, k: int) -> List[List[int]]: #在此之间填写代码 print(Solution().permute([1,2,3])) print(Solution().permute([0,1])) print(Solution().permute([1]))
2 解题思路
- 标签:回溯
- 回溯法 采用试错的思想,它尝试分步的去解决一个问题。
- 在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。
- 回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况:
- 找到一个可能存在的正确的答案;
- 在尝试了所有可能的分步方法后宣告该问题没有答案。
#3 解题方法
from typing import List class Solution: def permute(self, nums: List[int]) -> List[List[int]]: def backstack(first=0): if first==n: a.append(nums[:]) for i in range(first,n): nums[first],nums[i]=nums[i],nums[first] backstack(first+1) nums[first],nums[i]=nums[i],nums[first] a=[] n=len(nums) backstack() return a print(Solution().permute([1,2,3])) print(Solution().permute([0,1])) print(Solution().permute([1]))
第1-3,16-18行: 题目中已经给出的信息,运行代码时要根据这些代码进行编辑
第4行: 创建backtrack回溯函数,内部变量first用于固定一个值
第5行: 判断该值是否等于列表长度
第6行: 创建backtrack回溯函数,内部变量初始列表以及后面要求的列表以及限制条件
第7行: 若是,则本次列表遍历完成,将该结果加入总列表中
第8行: 使用for循环遍历从first值到列表长度的值
第9行: 将first对应的值与i对应的值交换
第10行: 对后面一段列表进行同样的操作
第11行: 回溯,变回之前的状态
第12行: 定义空列表a
第13行: 定义变量n用于存放列表长度
第14行: 进行回溯操作
第15行: 操作完成,返回a列表
代码运行结果为:
#算法讲解
这里用到了基础算法:回溯,简单讲解下这个算法:
回溯
回溯是很经典的一个算法,什么是回溯,回溯其实是一种暴力枚举的方式,为啥都暴力了还是很经典的一种方法呢,其实是因为有些问题我们能暴力出来就不错了,就别要其他自行车了。常见的回溯类问题:组合;排列;切割;子集;棋牌;
其实回溯算法就是常说的DFS,本质上是一种暴力枚举算法;
回溯算法常用于解决的问题:
组合
排列
切割
子集
棋盘:N皇后
比如最经典的排列。从1,2,3,4,5中取3个数组成排列有多少种,我们肯定会解决这种问题,但是程序怎么写呢。想一下我们解决这个问题的过程,我们先选1,然后第二个数可以选2,第三个数可以选3,这是一种答案了,然后呢,换第三个数,第三个数选4,又一种答案,再换,第三个数选5,没得选了,所以以12打头的数都选完了,得到三种答案.然后再换第二个数,第二个数选3,然后第三个数选4,注意是组合问题所以我们不能退往回选2了,不然就重复了。就是这样一种选择方案,一直到第3个数选成了3,得到答案345,就不用往后进行了。