前言
对于一些力扣题目,比如这次的全排列,或者是以前讲过的组合问题等,回溯方法都对它们有奇效,具有起死回生,盘活全局的作用,可谓是力扣之旅的必备良方!下面我来给你介绍介绍灵丹妙药————“回溯”
这是开出的回溯药方:
回溯模板
function backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
接下来我们来“看病”
题目
给定一个不含重复数字的数组 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]]
思路分析
这道题目的目的很明显,就是需要找到【1,2,3】的不重复的排列组合,注意是不要重复的。
做此类回溯题时,一般需要用到辅助空间,栈或者队列,比如我们代码当中用到的track是用来辅助暂时存储数据的栈,我们用图来看看自己用栈找结果的逻辑:
第一次栈的显示结果
第二次栈的显示结果
以上的图解还仅仅是一颗子树的解决方式,还有其他的两颗子树的路径也是相似,这里就不一一画出,我们来分析:
探索
在思考此类问题前呢,需要比较清晰的思维,这种回溯问题实际上“层层嵌套”的过程。我们需要想象出这种排列是一种怎么样的过程:根据我们自己想法所描绘出来的蓝图:
- 首先是让1进栈?2进栈?还是3进栈呢?,这三种情况都有,我们需要分别讨论,这个时候按顺序先让1进栈;
- 之后,让2 ,3进栈都行,那么此时又是两种情况,此时我们暂时让2进栈,
- 最后3进栈,那么此时这条路就走完了,因为接下来就没有数字了。
这就是回溯当中的深度优先遍历思想,“不撞南墙不回头”,一直将一条路进行到底,深度优先探索解二叉树,直到无路可走或者是找到了目标答案,否则不停下来,这是回溯当中很重要的思想。 在最后,我们就把找到的结果压进结果数组,返回即可。
回退
有的人就说了,我们第一次1,2,3的情况还没有分析完呢,这怎么整? 嘿嘿,别急慢慢来。
我们在上述情况当中已经找到了一组目标结果,但是如何讨论其他的情况呢?这个时候我们有需要了解回溯另外一种思想: 回退。简单来说就是回到上一步继续讨论原来未讨论完的情况。在回溯问题当中,这步骤很简单,就是track.pop(),是的你没有看错,就是出栈操作。这是怎么做到的呢?
比如我们找到了一组结果,【1,2,3】
,那么我们执行回退操作,直到还在【1】已经入栈,但是在2,3选择的这个时候,我们一开始是选择了2进栈,所以此时我们改变策略,让3进栈,那么此时又找到了一组结果,这个时候再次执行回退操作,直到我们最一开始的1,2,3
入栈选择的时候,我们再让 2 入栈即可,重复步骤,最后得出结果。
不过怎么模拟这个选择的过程呢?那就是循环。而且需要注意的是,这个地方要做去重操作。
虽然回溯的代码量较少,但是实际上你们也了解这个过程,空间上比较复杂,是典型的用空间换取时间的一种算法,但是依然改变不了他的适用性,仍然是力扣必备方法!
具体代码
var permute = function(nums) {
const result = []
backTrack(nums, result, [])
return result
};
function backTrack (nums, result, track) {
if (track.length === nums.length) {
// 更改引用类型的指针。目的;防止回溯行为影响到当前数组状态。
result.push([...track])
return
}
for (let i = 0; i < nums.length; i++) {
if (track.includes(nums[i])) {
continue
}
track.push(nums[i])
backTrack(nums, result, track)
track.pop()
}
}
代码分析
在这里需要定义我们的结果数组result[]
,这是用来存放最终结果的空间。而backTrack函数
就是我们的核心代码,其中套用了回溯模板,自行比对后你们可以发现,确实没啥两样。但是有一些细节需要注意,就是数组是否需要去重,比如这里,我们就使用了track.includes(nums[i])
的方法来跳过已经做出过选择的数字。
总结
总的来说,刷题有方法,我们需要根据做出的题目来总结出方法,不是说刷题多就有用,刷题只不过是给你们给予总结方法的经验,而不是给我们刷更多题目的动力,方向就走错了,所以说还是要多学习,多总结。
我是小白,我们一起力扣!