题目:
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]
]
解答:
解法一:回溯法
看到题目后立马会想到,这是一种典型的回溯思想,在之前的 LeetCode 17/22/29/30 题中,我们已经多次采用过回溯思想进行解答,此题采用的思路基本一致,回溯+递归。
注意:
- 对 nums 进行遍历时,要进行去重处理,即用
list.contains()
进行重复判断,如果 list 中出现过相同数字,就直接 continue - 回溯结束后,通过
list.remove(list.size()-1);
,去除 list 中最后一个元素,从而进行下一次循环
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> list = new ArrayList<>();
recursion(res, list, nums);
return res;
}
private void recursion(List<List<Integer>> res, List<Integer> list, int[] nums) {
if(list.size() == nums.length) {
res.add(new ArrayList<>(list));
return;
}
for(int i=0; i<nums.length; i++) {
if(list.contains(nums[i])) {
continue;
}
list.add(nums[i]);
recursion(res, list, nums);
list.remove(list.size()-1);
}
}
}
但提交结果显示效率并不算高,不是时间更优的解法。
解法二:字典排序
参看他人的解法,采用了字典排序的思想
在 LeetCode 31 题中,我们第一次接触了字典序算法,回顾:LeetCode 31. Next Permutation 下一个排列(字典序算法)
在31 题中,我们是根据字典序列的特点,寻找某一字典序列的下一个序列。这道题同理,先对nums进行排序,然后不断地寻找下一个排序,用 nextPermutation() 判断是否存在下一个排序,添加排序好的 list 时,采用do-while 循环能使得第一个排序好的数组先加入 res 中。(do-while 循环先执行循环体,后判断 while(true) 则进行下一次循环)
class Solution {
public List<List<Integer>> permute(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
do {
List<Integer> list = new ArrayList<>();
for (int num : nums) {
list.add(num);
}
res.add(list);
} while (nextPermutation(nums));
return res;
}
//判断是否有下一个排序,若没有则 return false
public boolean nextPermutation(int[] nums) {
if (nums.length == 1) {
return false;
}
int p = -1;
for (int i = nums.length - 2; i >= 0; i--) {
if (nums[i] < nums[i + 1]) {
p = i;
break;
}
}
if (p != -1) {
int temp = nums[p];
int q = nums.length - 1;
while (nums[q] <= temp) {
q--;
}
nums[p] = nums[q];
nums[q] = temp;
reverse(p + 1, nums);
} else {
return false;
}
return true;
}
public void reverse(int k, int[] nums) {
if (k >= nums.length) return;
int i = k;
int j = nums.length - 1;
while (i < j) {
int list = nums[i];
nums[i] = nums[j];
nums[j] = list;
i++;
j--;
}
}
}
解法三:递归
思路:以每个数开始的全排列,把每个数换到最前面一次,找到它后面数的所有全排列,把前面的数加上,作为一个 list,再把换到前面的数换回去,接着换下一个数
class Solution {
List<List<Integer>> result = new ArrayList<List<Integer>>();
public List<List<Integer>> permute(int[] nums) {
perm(nums, 0, nums.length-1);
return result;
}
public void perm(int[] nums, int start, int end){
if (start == end){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < nums.length; i++){
list.add(nums[i]);
}
this.result.add(list);
}else{
for (int i = start; i <= end; i++){
swap(nums,start, i);
perm(nums,start+1, end);
swap(nums, start, i);
}
}
}
public void swap(int[] nums,int p, int q){
int temp = nums[p];
nums[p] = nums[q];
nums[q] = temp;
}
}