NC+LC:全排列
无重复项
题目描述
给定一个不含重复数字的数组nums,返回其 所有可能的全排列 。
LeetCode中可按任意顺序返回答案,但牛客要求以数字在数组中的位置靠前为优先级,按字典序排列输出。
示例
输入:nums = [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
思路
实现代码1
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>(); //结果集合
List<Integer> list = new ArrayList<>();
for(int num : nums){ //将数组元素存入集合,直接对该集合进行处理
list.add(num);
}
backtrack(res, nums.length, list, 0);
return res;
}
public void backtrack(List<List<Integer>> res, int length, List<Integer> list, int start) {
if (start == length) { //递归终止条件,遍历到了数组末尾
res.add(new ArrayList<Integer>(list)); //需新建一个集合对象存入
return;
}
for (int i = start; i < length; i++) {
//将start上的元素依次与后面的元素进行交换
Collections.swap(list, start, i);
//递归
backtrack(res, length, list, start+1);
//回溯上一个start的位置,保证与其他位置进行同样的交换
Collections.swap(list, start, i);
}
}
} 实现代码2
使用类似深度优先遍历(DFS)的做法
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>(); //结果集合
int[] visited = new int[nums.length]; //标记访问过的位置
backtrack(res, nums, new ArrayList<Integer>(), visited);
return res;
}
public void backtrack(List<List<Integer>> res, int[] nums, ArrayList<Integer> tmp, int[] visited) {
if (tmp.size() == nums.length) { //递归终止条件
res.add(new ArrayList<>(tmp));
return;
}
for (int i = 0; i < nums.length; i++) {
if (visited[i] == 1) continue;
visited[i] = 1;
tmp.add(nums[i]);
//递归访问没访问过的位置
backtrack(res, nums, tmp, visited);
//在回溯过程中还原到上一状态
visited[i] = 0;
tmp.remove(tmp.size() - 1);
}
}
} 有重复项
LC 47.全排列 II:https://leetcode-cn.com/problems/permutations-ii/
题目描述
给定一个可包含重复数字的序列nums,按任意顺序 返回所有不重复的全排列。
示例
输入:nums = [1,1,2] 输出:[[1,1,2],[1,2,1],[2,1,1]]
思路
回溯法(在题目LC 46.全排列的基础进行修改,修改1:先将数组进行排序,使重复元素聚集在一起;修改2:接着通过判断当前元素与前一个元素是否相等,且前一元素是否被访问过来决定是否进行排列)
重点代码:
if (i > 0 && nums[i] == nums[i-1] && visited[i-1] == 0){
continue;
} 实现代码
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>(); //结果集合
int[] visited = new int[nums.length]; //标记访问过的位置
Arrays.sort(nums); //排序,这样重复元素会聚集在一起
backtrack(res, nums, new ArrayList<Integer>(), visited);
return res;
}
public void backtrack(List<List<Integer>> res, int[] nums, ArrayList<Integer> tmp, int[] visited) {
if (tmp.size() == nums.length) { //递归终止条件,遍历到了数组末尾
res.add(new ArrayList<>(tmp));
return;
}
for (int i = 0; i < nums.length; i++) {
//若当前元素与前一个元素相等,且前一元素未被访问过,就直接跳过,避免重复排列
if (i > 0 && nums[i] == nums[i-1] && visited[i-1] == 0){
continue;
}
if(visited[i] == 0){
visited[i] = 1;
tmp.add(nums[i]);
//递归访问没访问过的位置
backtrack(res, nums, tmp, visited);
//在回溯过程中还原到上一状态
visited[i] = 0;
tmp.remove(tmp.size() - 1);
}
}
}
} 