1.题目描述
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
2.思路和算法
这个问题可以看做是n个排列成一行的空格,我们需要从左往右依此填入题目给定的 n 个数,每个数只能使用一次。那么很直接的可以想到一种穷举的算法,即从左往右每一个位置都依此尝试填入一个数,看能不能填完这 nn 个空格,在程序中我们可以用「回溯法」来模拟这个过程。
我们定义递归函数dfs(first, output) 表示从左往右填到第first 个位置,当前排列为output。 那么整个递归函数分为两个情况:
- 如果first==n,说明我们已经填完了 n 个位置(注意下标从 0开始),找到了一个可行的解,我们将 \textit{output}output 放入答案数组中,递归结束。
- 如果 first<n,我们要考虑这第first 个位置我们要填哪个数。根据题目要求我们肯定不能填已经填过的数,因此很容易想到的一个处理手段是我们定义一个标记数组vis[] 来标记已经填过的数,那么在填第first 个数的时候我们遍历题目给定的 n 个数,如果这个数没有被标记过,我们就尝试填入,并将其标记,继续尝试填下一个位置,即调用函数dfs(first + 1, output)。搜索回溯的时候要撤销这一个位置填的数以及标记,并继续尝试其他没被标记过的数
下面的图展示实例搜索的整个过程:
3.通过源代码
完整代码:
import java.util.ArrayList;
import java.util.List;
public class PermuteAll {
List<Integer> ans=new ArrayList<>();
List<List<Integer>> res=new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
boolean []visted=new boolean[nums.length];
dfs(nums,visted);
return res;
}
void dfs(int[] nums,boolean []visted){
if(ans.size()==nums.length){
res.add(new ArrayList<>(ans));
return;
}
for(int i=0;i<nums.length; i++){
if(visted[i] == true) {
continue;
}
visted[i]=true;
ans.add(nums[i]);
dfs(nums,visted);
ans.remove(ans.size()-1);
visted[i]=false;
}
}
public static void main(String[] args) {
int []nums={1,2,3};
PermuteAll p1=new PermuteAll();
List<List<Integer>> res=new ArrayList<>();
res=p1.permute(nums);
System.out.println(res.toString());
}
}
本地运行截图:
提交Leetcode代码截图: