题目详情
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
该题是一到比较简单而且经典的回溯题,或者说是排列组合穷举题,这种题只要回溯(dfs+删除操作)即可完成,写本文的目的在于,一是记录下回溯的一般写法,二是提醒自己关于java中的引用一定要注意。
题目分析
对于回溯问题的一般思路就是:
def backtrack(路径,选择列表):
if满足条件:
添加到最终结果
return
for 选择 in 选择列表:
做选择
backtrack(路径,选择列表)
撤销选择
(这个是我在LeetCode评论区看来的,觉得挺好,@Teki)
基本就是这个思路就可以完成代码的书写。
我这里的代码写的稍稍有些冗余,其实可以不用标记数组,直接用List的contains方法即可,(这里mark一下,以后就用这个),因为平时java使用的还是有些少,比较生疏。
贴上代码:
//有思路了,就是建立一个marked数组,记录标记情况,然后for循环,跳过标记的,然后一直往下搜索就行如
//可以判断一下数组的和是否等于长度来判断是否完了
//总体还是很简单的
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> results = new LinkedList<>();
if(nums==null||nums.length==0)
return results;
for(int i=0;i<nums.length;i++)
{
int[] marked = new int[nums.length];
backtrack(nums,i,marked,new LinkedList<Integer>(),results,0);
}
return results;
}
public void backtrack(int[] nums, int index, int[] marked, LinkedList<Integer> result, List<List<Integer>> results,int count){
//count用于判断当前是否满了
if(count==nums.length-1&&marked[index]==0){
result.add(nums[index]);
// System.out.println(result);
results.add((List<Integer>)result.clone());//这里需要进行一个拷贝,不然里面存的都是一个变量,最后值都为0了
result.remove(result.size()-1);
return;
}
//判断当前索引是否被遍历过
if(marked[index]==1)
return;
//如果都没有,则说明可以遍历
//先把自己放进result中去
result.add(nums[index]);
marked[index]=1;
count++;
//再从头开始遍历
for(int j=0;j<nums.length;j++)
backtrack(nums,j,marked,result,results,count);
//最终把自己删掉
// System.out.println(nums[index]);
result.remove(result.size()-1);
marked[index]=0;
count--;
}
这里,在results.add((List<Integer>)result.clone());
这一行,我一开始写的是results.add(result)
,结果就导致了最后输出的结果都是空(因为回溯),想了一会儿才想起来,这里不是基本类型,而是引用类型,所以必须要进行一次拷贝,然后发现List无法用clone,查了一会儿才发现,哦原来要用LinkedList或者ArrayList才可以,然后再需要一次强制类型转换。