Given a collection of numbers, return all possible permutations.
For example,
[1,2,3]
have the following permutations:
[1,2,3]
, [1,3,2]
, [2,1,3]
, [2,3,1]
, [3,1,2]
, and [3,2,1]
.
public class Solution {
private ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
public void dfs(int[] num, int pos){
if(pos == num.length){
ArrayList<Integer> l = new ArrayList<Integer>();
for(int i=0; i<num.length; i++)
l.add(num[i]);
res.add(l);
return;
}
for(int i=pos; i<num.length; i++){//exchange
int temp = num[pos];
num[pos] = num[i];
num[i] = temp;
dfs(num, pos+1);//pos遍历层次
num[i] = num[pos];
num[pos] = temp;
}
}
public ArrayList<ArrayList<Integer>> permute(int[] num) {
Arrays.sort(num);
dfs(num, 0);
return res;
}
}
解法二:参考
http://blog.csdn.net/u011095253/article/details/9158403
这次,我们要生成完整的序列了,那么和上次的Subset有什么不同呢?
1. 添加进res的时间,上面题我们每添加一个数字到tmp里,就可以往res里面添加,而这次,我们要生成完整的序列,所以需要当tmp.size()==序列长度的时候再往res里面添加
2. 每次不能从pos开始往数组尾巴扫了,因为我们要求的不是Subset而是完整序列,所以要从第一个数字开始往数组尾巴扫,问题又来了,我们怎么知道取没取过这个元素呢,那么我们就创建一个boolean[] visit 每此添加的时候给相对应位置置True,删去的时候置False
public class Solution {
private ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
public void dfs(ArrayList<Integer> l, int[] num, int[] flag){
if(l.size() == num.length){
res.add(new ArrayList(l));
return;
}
for(int i=0; i<num.length; i++){
if(flag[i] == 1) continue;
l.add(num[i]);
flag[i] = 1;
dfs(l, num, flag);//不是new ArrayList(l)
l.remove(l.size() -1);
flag[i] = 0;
}
}
public ArrayList<ArrayList<Integer>> permute(int[] num) {
ArrayList<Integer> l = new ArrayList<Integer>();
int [] flag = new int[num.length];
Arrays.sort(num);
dfs(l,num,flag);
return res;
}
}
解法三:使用字典序法
public class Solution {
private ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
public ArrayList<ArrayList<Integer>> permute(int[] num) {
int [] flag = new int[num.length];
Arrays.sort(num);
int i = num.length-1;
int pos, j;
while(i>=0){
ArrayList<Integer> l = new ArrayList<Integer>();
for(int k=0; k<num.length; k++){
l.add(num[k]);
}
res.add(l);
pos = i-1;
while(pos>=0 && pos<num.length-1 && num[pos] >= num[pos+1]) pos--;//从后往前求num[i]<num[i+1]的节点i
if(pos >= 0){//若已经按大到小的顺序排列则推出循环,否则,从后往前求比i节点大的节点
j = num.length - 1;
while(j>=0 && num[j] <= num[pos]) j--;//节点j,num[j]>num[i]
if(j>=0)
swap(num, pos, j);//交换i,j
if(pos < num.length-1)
reverse(num, pos+1);//将i后的所有节点反转
i = num.length-1;//重新从最后一个节点求
}
else{
break;
}
}
return res;
}
public void reverse(int [] num, int pos){
for(int i=num.length-1; i>=pos;){
int temp = num[i];
num[i] = num[pos];
num[pos] = temp;
i--;
pos++;
}
}
public void swap(int[] num, int i, int j){
int temp = num[i];
num[i] = num[j];
num[j] = temp;
}
}