【常见面试算法】全排列、子集
全排列和子集都是非常常见的DFS面试问题,因此把他俩放到一起来说,同时分析一下他们的不同,加强对回溯法和出递归条件的判断理解。
全排列II
全排列要考虑数组有重复的情况,因此我们要先对原数组进行一个排序(不排序也可以,但是需要牺牲空间,用一个set来保存结果)。
我们看原题:
输入一个字符串,打印出该字符串中字符的所有排列。
例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
如果无重复,则题解为:
class Solution { public List<List<Integer>> permutation(int[] nums) { List<List<Integer>> resList = new ArrayList<>(); if (nums == null || nums.length == 0) { return resList; } dfs(nums, resList, 0); return resList; } private void dfs(int[] nums, List<List<Integer>> resList, int index) { if (index == nums.length) { List<Integer> res = new ArrayList<>(); for (int i = 0; i < nums.length; i++) { res.add(nums[i]); } resList.add(res); return; } for (int i = index; i < nums.length; i++) { swap(nums,i,index); dfs(nums, resList, index + 1); swap(nums,i,index); } } private void swap(int[] nums, int a, int b) { int tmp = nums[a]; nums[a] = nums[b]; nums[b] = tmp; } }
如果有重复,则题解为:
提供一种不同的思路,不用swap做,而使用tmp数组保存结果。 class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
int[] visited = new int[nums.length];
backtrack(res, nums, visited, new ArrayList<Integer>());
return res;
}
private void backtrack(List<List<Integer>> res, int[] nums, int[] visited, ArrayList<Integer> tmp) {
if (tmp.size() == nums.length) {
res.add(new ArrayList<>(tmp));
return;
}
for (int i = 0; i < nums.length; i++) {
if (visited[i] == 1 || (i > 0 && visited[i - 1] == 0 && nums[i - 1] == nums[i])) continue;
visited[i] = 1;
tmp.add(nums[i]);
backtrack(res, nums, visited, tmp);
tmp.remove(tmp.size() - 1);
visited[i] = 0;
}
}
}
子集II
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。说明:解集不能包含重复的子集。
示例:
输入: [1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subsets-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution { public List<List<Integer>> subsetsWithDup(int[] nums) { List<List<Integer>> res = new ArrayList<>(); List<Integer> list = new ArrayList<>(); Arrays.sort(nums); findAll(0,nums,list,res); return res; } public static void findAll(int index, int[] nums, List<Integer> list, List<List<Integer>> res) { res.add(new ArrayList<>(list)); for (int i = index; i < nums.length; i++) { if (i != index && nums[i] == nums[i - 1]){ continue; } list.add(nums[i]); findAll(i + 1, nums, list, res); list.remove(list.size() - 1); } } }