给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutations
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
两种解法,一种回溯,一种字典序。
回溯:比较简单,直接上代码
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
//回溯法
//per(0,nums,result);
return result;
}
//回溯
private void per(int cur,int[] nums,List<List<Integer>> result){
//cur指针走到数组最后,记录值,并返回
if(cur == nums.length-1){
add(nums,result);
return;
}
//固定一位后,递归交换下一位
for(int i = cur;i<nums.length;i++){
//交换
swap(cur,i,nums);
//递归
per(cur+1,nums,result);
//回溯
swap(cur,i,nums);
}
}
private void add(int[] nums, List<List<Integer>> result){
List<Integer> list = new ArrayList<>();
for(int i = 0;i<nums.length;i++){
list.add(nums[i]);
}
result.add(list);
}
//对换
private void swap(int i ,int j,int[] nums){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
字典序:
通过字典序算法来获得下一个字典序,但需要先从小到大排序。
字典序算法:
(1)从右向左找到第一个下标为i,其中nums[i]<nums[i+1],记录i
(2)从右向左找到第一个比i大的数,下标为j,交换i,j,
(3)此时i+1之后的数字为从大到小排列,翻转i+1至数组末尾的数据,得到下一个排列。
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
//字典序算法
Arrays.sort(nums);
add(nums,result);
while(getNextDictionaryPreface(nums)){
add(nums,result);
}
return result;
}
private void add(int[] nums, List<List<Integer>> result){
List<Integer> list = new ArrayList<>();
for(int i = 0;i<nums.length;i++){
list.add(nums[i]);
}
result.add(list);
}
//对换
private void swap(int i ,int j,int[] nums){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
//得到下一个字典序
private boolean getNextDictionaryPreface(int[] nums){
//如果长度为1,则没有下一个字典序
if(nums.length<=1 || nums == null) return false;
//从右到左找到第一个左边小于右边的数,并记录
int jiluleft = -1;
for (int i = nums.length-2; i>=0 ;i--){
if(nums[i] < nums[i+1]){
jiluleft = i;
break;
}
}
//若jiluleft值不变,说明没有下一个字典序,例如{4,3,2,1}
if(jiluleft == -1)
return false;
else{
//从右到左找到第一个大于nums[jiluleft]的数,并交换
for (int i = nums.length-1; i>=jiluleft ;i--){
if(nums[i] > nums[jiluleft]){
swap(jiluleft,i,nums);
break;
}
}
//翻转left+1至数组末尾
reversalNums(jiluleft+1,nums.length-1,nums);
return true;
}
}
//翻转数组
private void reversalNums(int left,int right,int[] nums){
while(right > left){
swap(left,right,nums);
left++;right--;
}
}