组合
组合类的解空间树一般都有二叉树和多叉树两种。
组合
写法一:
考虑每个数选或不选,解空间树为二叉树。
解空间树如下。
class Solution {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> res = new ArrayList<>();
dfs(res, new ArrayList<>(), n, k, 1);
return res;
}
public void dfs(List<List<Integer>> res, List<Integer> list, int n, int k, int t) {
// 递归结束的条件
// t等于n+1时,n选或不选方可确定
if (t == n + 1) {
if (list.size() == k) {
res.add(new ArrayList<>(list));
}
return;
}
// 选择t
list.add(t);
dfs(res, list, n, k, t + 1);
// 不选择t
list.remove(list.size() - 1);
dfs(res, list, n, k, t + 1);
}
}
写法二:
考虑
解空间树如下。
或
public class Solution {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> res = new ArrayList<>();
dfs(n, k, 1, new ArrayList<>(), res);
return res;
}
private void dfs(int n, int k, int begin, List<Integer> path, List<List<Integer>> res) {
// 递归终止条件是:path 的长度等于 k
if (path.size() == k) {
res.add(new ArrayList<>(path));
return;
}
// 第begin轮, 从[begin..n]中依次只选择一个
for (int i = begin; i <= n; i++) {
// 选择i进入下一轮
path.add(i);
dfs(n, k, i + 1, path, res);
// 恢复原状
path.remove(path.size() - 1);
}
}
}
组合总和
leetcode-cn.com/problems/co…
写法一:
解空间树如下。
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
dfs(candidates, target, 0, new ArrayList<>(), res);
return res;
}
private void dfs(int[] arr, int target, int t, List<Integer> list, List<List<Integer>> result) {
if (t == arr.length) {
return;
}
if (target == 0) {
result.add(new ArrayList(list));
return;
}
// 不选择t
dfs(arr, target, t + 1, list, result);
// 满足条件才选择t
if (arr[t] <= target) {
list.add(arr[t]);
dfs(arr, target - arr[t], t, list, result);
list.remove(list.size() - 1);
}
}
}
写法二:
解空间树如下。
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
dfs(candidates, target, 0, new ArrayList<>(), res);
return res;
}
private void dfs(int[] arr, int target, int t, List<Integer> list, List<List<Integer>> result) {
if (target <= 0) {
if (target == 0) {
result.add(new ArrayList(list));
}
return;
}
//
for (int i = t; i < arr.length; i++) {
list.add(arr[i]);
// 递归继续从i开始,因为元素可以重复选择
dfs(arr, target - arr[i], i, list, result);
list.remove(list.size() - 1);
}
}
}
组合总和II
leetcode-cn.com/problems/co… 写法一:
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(candidates);
dfs(candidates, target, res, new ArrayList<>(), 0);
return res;
}
private void dfs(int[] candidates, int target, List<List<Integer>> res, List<Integer> list, int t) {
if (target == 0) {
res.add(new ArrayList<>(list));
return;
}
if (target < 0 || t > candidates.length - 1) {
return;
}
// 左子树:选择t
list.add(candidates[t]);
dfs(candidates, target - candidates[t], res, list, t + 1);
// 右子树:不选择t
list.remove(list.size() - 1);
t++;
// 防止 [选择x,不选择x]和[不选择x,选择x]两种重复
while (t < candidates.length && candidates[t] == candidates[t - 1]) {
t++;
}
dfs(candidates, target, res, list, t);
}
}
写法二:
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(candidates);
dfs(candidates, target, res, new ArrayList<>(), 0);
return res;
}
private void dfs(int[] candidates, int target, List<List<Integer>> res, List<Integer> list, int t) {
if (target == 0) {
res.add(new ArrayList<>(list));
return;
}
if (target < 0 || t > candidates.length - 1) {
return;
}
for (int i = t; i < candidates.length; i++) {
// 不同分支间不允许取相同元素,否则会出现[1,7]和[1*,7]这种重复
// i == t时,是一个分支的上下节点间,允许[1,1*,7]这种
if (i > t && candidates[i] == candidates[i - 1]) {
continue;
}
list.add(candidates[i]);
dfs(candidates, target - candidates[i], res, list, i + 1);
list.remove(list.size() - 1);
}
}
}
组合总和III
leetcode-cn.com/problems/co… 写法一:
class Solution {
public List<List<Integer>> combinationSum3(int k, int n) {
List<List<Integer>> res = new ArrayList<>();
dfs(n, k, 1, res, new ArrayList<>());
return res;
}
private void dfs(int n, int k, int t, List<List<Integer>> res, List<Integer> list) {
if (n < 0 || list.size() > k || t > 10) {
return;
}
if (n == 0 && list.size() == k) {
res.add(new ArrayList<>(list));
return;
}
list.add(t);
dfs(n - t, k, t + 1, res, list);
list.remove(list.size() - 1);
dfs(n, k, t + 1, res, list);
}
}
写法二:
class Solution {
public List<List<Integer>> combinationSum3(int k, int n) {
List<List<Integer>> res = new ArrayList<>();
dfs(n, k, 1, res, new ArrayList<>());
return res;
}
private void dfs(int n, int k, int t, List<List<Integer>> res, List<Integer> list) {
if (n < 0 || list.size() > k || t > 10) {
return;
}
if (n == 0 && list.size() == k) {
res.add(new ArrayList<>(list));
return;
}
for (int i = t; i < 10; i++) {
list.add(i);
dfs(n - i, k, i + 1, res, list);
list.remove(list.size() - 1);
}
}
}
组合总和IV
leetcode-cn.com/problems/co… 这道题回溯翻车了,要用动态规划。
排列
全排列
class Solution {
private List<List<Integer>> res;
public List<List<Integer>> permute(int[] nums) {
res = new ArrayList<>();
permute(nums, 0);
return res;
}
private void permute(int[] nums, int t) {
if (t == nums.length) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
list.add(nums[i]);
}
res.add(list);
return;
}
for (int i = t; i < nums.length; i++) {
swap(nums, i, t);
permute(nums, t + 1);
swap(nums, i, t);
}
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
全排列II
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
dfs(nums, 0, res);
return res;
}
private void dfs(int[] nums, int t, List<List<Integer>> res) {
if (t == nums.length) {
List<Integer> list = new ArrayList<>();
for (int i : nums) {
list.add(i);
}
res.add(new ArrayList<>(list));
return;
}
// 每个元素轮流换到t位置上,包括t上本身的元素
for (int i = t; i < nums.length; i++) {
// 如果前面某个元素去过一次t位置,后面相等的元素就不再去t上了
// 例如1,1*,2, 1与1“交换”过,1*不再与1交换
boolean b = false;
for (int j = t; j < i; j++) {
if (nums[j] == nums[i]) {
b = true;
}
}
if (b) {
continue;
}
swap(nums, i, t);
dfs(nums, t + 1, res);
swap(nums, i, t);
}
}
private void swap(int[] nums, int i, int j) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
}