题目
Given a collection of distinct integers, return all possible permutations.
Example:
Input: [1,2,3]
Output:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
注意,不同的整数,相同可能有变化
十分钟尝试
应该是缺少这些问题的思路,直接看思路,果然回溯法。先看看回溯法是什么意思
回溯法
backtracking(回溯法)是一类递归算法,通常用于解决某类问题:要求找出答案空间中符合某种特定要求的答案,比如eight queens puzzle(将国际象棋的八个皇后排布在8x8的棋盘中,使她们不能互相威胁)。回溯法会增量性地找寻答案,每次只构建答案的一部分,在构建的过程中如果意识到答案不符合要求,会立刻将这一部分答案及它的所有子答案抛弃,以提高效率。
回溯法的核心模型是一个决策树,每个节点的子节点代表该节点的选项。从根节点出发,作出某种选择达到节点A,随后会面临节点A的选项,重复这个过程直到达到叶节点。如果途中发现某节点B的状态已经不符合要求,那么弃掉以B为根节点的子决策树。
到达叶节点时,判断其是否符合问题要求,然后根据情况作相应处理(如将符合要求的叶节点加入一个list)。叶节点没有子节点,因此回溯到上一个访问过的节点,以尝试其他选择。当我们最终回溯到根节点,且已经穷尽了根节点的所有选择时,算法结束。
在上图的决策树中,用good和bad分别代表符合和不符合要求的叶节点。回溯法的遍历过程是这样的:
- 从Root开始,有A和B两个选项。选择A。
- 从A开始,有C和D两个选项。选择C。
- C不符合要求,回溯到A。
- A处的剩余选项为D。选择D。
- D不符合要求,回溯到A。
- A的选项已穷尽,回溯到Root。
- Root处的剩余选项为B。选择B。
- 从B开始,有E和F两个选项。选择E。
- E符合要求,将其加入某个list,回溯到B。
- B出的剩余选项为F。选择F。
- F不符合要求。回溯到B。
- B的选项已穷尽,回溯到Root。
- Root的选项已穷尽。结束。
本文给出leetcode上数组排列组合问题的回溯法解答。这些问题大多为“返回某数组/字符串的所有排列/组合”类型,没有提出明确的要求来筛选叶节点。看起来,似乎简单地使用回溯法遍历决策树即可,但是在实现中会遇到一些棘手的小问题,比如每一个选项如何定义,如何记录某一个节点上已经选择过的选项等。学习回溯法时,可以先从这些问题开始熟悉回溯法的套路,熟练后再去解决更复杂的问题。
正确解法
虽然看了回溯法,但是这个题目作者说用的回溯法,感觉更像是递归。代码不容易理解,我手写了下面的过程,方便大家理解,先看图:
代码如下:
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> list=new ArrayList();
backTrace(list,new ArrayList(),nums);
return list;
}
private void backTrace(List list,List<Integer> tmpList,int[] nums){
if(tmpList.size()==nums.length){
//全局返回的list就在这添加元素,其他地方都是tmplist
list.add(new ArrayList(tmpList));
}
else{
for(int i=0;i<nums.length;i++){
if(tmpList.contains(nums[i])){
continue;
}
tmpList.add(nums[i]);
backTrace(list,tmpList,nums);
tmpList.remove(tmpList.size()-1);
}
}
}
}