46. 全排列
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
dfs(0, nums, 0);
return res;
}
void dfs(int u, int[] nums, int st) {
if (u == nums.length) {
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < nums.length; i++) {
if ((st >> i & 1) == 1)
continue;
path.add(nums[i]);
dfs(u + 1, nums, st | (1 << i));
path.remove(path.size() - 1);
}
}
}
当然path也可以用整型数组代替 st也能用boolean数组代替
47. 全排列 II
// 多了排序 + 判重的步骤
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
Arrays.sort(nums);
dfs(0, nums, 0);
return res;
}
void dfs(int u, int[] nums, int st) {
if (u == nums.length) {
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < nums.length; i++) {
if ((st >> i & 1) == 1 || (i > 0 && nums[i] == nums[i - 1] && (st >> (i - 1) & 1) == 0))
continue;
path.add(nums[i]);
dfs(u + 1, nums, st | (1 << i));
path.remove(path.size() - 1);
}
}
}
77. 组合
// 方法1 dfs
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> combine(int n, int k) {
dfs(1, 1, n, k);
return res;
}
void dfs(int u, int start, int n, int m) {
if (u == m + 1) {
res.add(new ArrayList<>(path));
return;
}
for (int i = start; i + m - u <= n; i++) {
path.add(i);
dfs(u + 1, i + 1, n, m);
path.remove(path.size() - 1);
}
}
}
// 方法2:二进制枚举
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> combine(int n, int k) {
for (int i = 0; i < 1 << n; i++) {
if (Integer.bitCount(i) != k) continue;
List<Integer> path = new ArrayList<>();
for (int j = 0; j < n; j++) {
if ((i >> j & 1) == 1) {
path.add(j + 1);
}
}
res.add(path);
}
return res;
}
}
二进制枚举不能保证输出为字典序
40. 组合总和 II
// 排序 + 按层剪枝 + 可行性剪枝
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
dfs(0, candidates, 0, target);
return res;
}
void dfs(int u, int[] candidates, int sum, int target) {
if (sum == target) {
res.add(new ArrayList<>(path));
return;
}
for (int i = u; i < candidates.length && sum + candidates[i] <= target; i++) {
if (i > u && candidates[i] == candidates[i - 1])
continue;
path.add(candidates[i]);
dfs(i + 1, candidates, sum + candidates[i], target);
path.remove(path.size() - 1);
}
}
}
78. 子集
方法1:二进制枚举
class Solution {
public List<List<Integer>> subsets(int[] nums) {
int n = nums.length;
List<List<Integer>> res = new ArrayList<>();
for (int i = 0; i < 1 << n; i++) {
List<Integer> path = new ArrayList<>();
for (int j = 0; j < n; j++) {
if ((i >> j & 1) == 1)
path.add(nums[j]);
}
res.add(path);
}
return res;
}
}
// 方法2 dfs
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
dfs(0, nums);
return res;
}
void dfs(int startIndex, int[] nums) {
res.add(new ArrayList<>(path));
for (int i = startIndex; i < nums.length; i++) {
path.add(nums[i]);
dfs(i + 1, nums);
path.remove(path.size() - 1);
}
}
}
90. 子集 II
// 方法一 二进制枚举
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
int n = nums.length;
List<List<Integer>> res = new ArrayList<>();
label: for (int i = 0; i < 1 << n; i++) {
List<Integer> path = new ArrayList<>();
for (int j = 0; j < n; j++) {
if ((i >> j & 1) == 1) {
if (j > 0 && nums[j] == nums[j - 1] && (i >> (j - 1) & 1) == 0)
continue label;
path.add(nums[j]);
}
}
res.add(path);
}
return res;
}
}
// 方法2 排序 + 按层判重
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
int n;
public List<List<Integer>> subsetsWithDup(int[] nums) {
n = nums.length;
Arrays.sort(nums);
dfs(0, nums);
return res;
}
void dfs(int u, int[] nums) {
res.add(new ArrayList<>(path));
for (int i = u; i < n; i++) {
if (i > u && nums[i] == nums[i - 1])
continue;
path.add(nums[i]);
dfs(i + 1, nums);
path.remove(path.size() - 1);
}
}
}
// 方法3 排序 + 判重数组(判重数组也可以用二进制数记录)
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
int n;
public List<List<Integer>> subsetsWithDup(int[] nums) {
n = nums.length;
Arrays.sort(nums);
boolean[] st = new boolean[n];
dfs(0, nums, st);
return res;
}
void dfs(int u, int[] nums, boolean[] st) {
res.add(new ArrayList<>(path));
for (int i = u; i < n; i++) {
if (i > u && nums[i] == nums[i - 1] && !st[i - 1])
continue;
path.add(nums[i]);
st[i] = true;
dfs(i + 1, nums, st);
st[i] = false;
path.remove(path.size() - 1);
}
}
}
// 方法4 排序 + 层内Set
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
int n;
public List<List<Integer>> subsetsWithDup(int[] nums) {
n = nums.length;
Arrays.sort(nums);
dfs(0, nums);
return res;
}
void dfs(int u, int[] nums) {
res.add(new ArrayList<>(path));
Set<Integer> set = new HashSet<>();
for (int i = u; i < n; i++) {
if (set.contains(nums[i]))
continue;
set.add(nums[i]);
path.add(nums[i]);
dfs(i + 1, nums);
path.remove(path.size() - 1);
}
}
}