给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = [0]
输出:[[],[0]]
提示:
任意一个子集,都可以用全部数组元素,每个元素包含,或不包含来表示。假如包含记为1,不包含记为0。如 [1, 2, 3] ,那么可以表示为
子集 | 0/1序列 |
---|---|
[] | 000 |
[1] | 001 |
[2] | 010 |
[3] | 100 |
[1, 2] | 011 |
[1, 3] | 101 |
[2, 3] | 110 |
[1, 2, 3] | 111 |
可以发现 0/1 序列二进制数的范围,刚好是十进制从 0 到 2 n − 1 2^n-1 2n−1。那么,我们要做的,其实就只是把这个范围的数,按二进制,取每一位的数字,如果为1,表示原数组同样的索引位置,存放的元素存在子集中
class Solution {
public List<List<Integer>> subsets(int[] nums) {
int n = nums.length;
List<List<Integer>> subset = new ArrayList<>();
for(int i = 0;i < (1 << n);i++) {
List<Integer> sub = new ArrayList<>();
for(int j = 0;j < n;j++) {
if(((i >> j) & 1) == 1) {
sub.add(nums[j]);
}
}
subset.add(sub);
}
return subset;
}
}
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
示例 1:
输入:n = 4, k = 2
输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]
示例 2:
输入:n = 1, k = 1
输出:[[1]]
提示:
假如 n=4, k=2 ,即要在 [1, 2, 3, 4] 中求 2 个数的组合。
那么对每个组合来说, 1~4 范围内的每个数字都只有 包含 与 不包含 两种情况
则 dfs(1, 4) 可以分解为 dfs(1) 的组合与 dfs(2, 4) 组合:
(1) dfs(1) 为 1 的组合,即 [1] (包含 1 )、 [] (不包含 1 )。
(2)如果 dfs(1) 包含1,则 dfs(2, 4) 需要有 k-1=2-1=1 个元素来构建组合
(3)如果 dfs(1) 不包含1,则 dfs(2, 4) 需要有 k-0=2 个元素来构建组合
同样的, dfs(2, 4) = dfs(2) + dfs(3, 4) dfs(3, 4) = dfs(3) + dfs(4) 。
由以上分解的问题,最终可以采取如下步骤:
class Solution {
List<List<Integer>> ret = new ArrayList<>();
Deque<Integer> sub = new ArrayDeque<>();
public List<List<Integer>> combine(int n, int k) {
dfs(n,k,1);
return ret;
}
private void dfs(int n,int k,int cur) {
if(sub.size() == k) {
ret.add(new ArrayList(sub));
return;
}
for(int i = cur;i <= n;i++) {
sub.addLast(i);
dfs(n,k,i+1);
sub.removeLast();
}
}
}
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:
输入:nums = [1]
输出:[[1]]
提示:
class Solution {
List<List<Integer>> ret = new ArrayList<>();
Deque<Integer> sub = new ArrayDeque<>();
public List<List<Integer>> permute(int[] nums) {
backTrack(nums);
return ret;
}
private void backTrack(int[] nums) {
if(sub.size() == nums.length) {
ret.add(new ArrayList(sub));
return;
}
for(int i = 0;i < nums.length;i++) {
if(!sub.contains(nums[i])) {
sub.addLast(nums[i]);
backTrack(nums);
sub.removeLast();
}
}
}
}
给定一个可包含重复数字的序列 nums ,按任意顺序返回所有不重复的全排列。
示例 1:
输入:nums = [1,1,2]
输出: [[1,1,2], [1,2,1], [2,1,1]]
示例 2:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
提示:
数组中包含了重复的数字,要求我们返回不重复的全排列,那么,我们可以将数组升序排序,这样如果相邻元素一样,在决策树就可以不选择同一层中,和上一个相同的元素
要判断同一层中的相邻元素,即数组相邻元素是否一样,需要再维护一个数组每个元素状态的列表:可以设置为boolean 数组,长度和原数组一样,当已选择,则同索引上的状态设为 true 。这样,我们在路径中,选择元素时,就可以不选择:
class Solution {
List<List<Integer>> ret = new ArrayList<>();
Deque<Integer> sub = new ArrayDeque<>();
boolean[] visits;
public List<List<Integer>> permuteUnique(int[] nums) {
visits = new boolean[nums.length];
Arrays.sort(nums);
backTrack(nums);
return ret;
}
private void backTrack(int[] nums) {
if(sub.size() == nums.length) {
ret.add(new ArrayList(sub));
return;
}
for(int i = 0;i < nums.length;i++) {
if(visits[i] ||(i > 0 && nums[i] == nums[i-1] && !visits[i-1])) {
continue;
}
sub.addLast(nums[i]);
visits[i] = true;
backTrack(nums);
sub.removeLast();
visits[i] = false;
}
}
}
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:[“((()))”,“(()())”,“(())()”,“()(())”,“()()()”]
示例 2:
输入:n = 1
输出:[“()”]
提示:
本题属于全排列的一种变形,可以看出,输出的结果,为 n 个左括号,与 n 个右括号,在满足 左括号必须以正确的顺序闭合条件下的全排列。
本题使用搜索回溯算法+剪枝来实现
class Solution {
List<String> ret = new ArrayList<>();
StringBuilder path = new StringBuilder();
public List<String> generateParenthesis(int n) {
backtrack(n,0,0);
return ret;
}
private void backtrack(int n,int left,int right) {
if(path.length() == n*2) {
ret.add(path.toString());
return;
}
if(left < n) {
path.append('(');
backtrack(n,left+1,right);
path.deleteCharAt(path.length()-1);
}
if(right < left) {
path.append(')');
backtrack(n,left,right+1);
path.deleteCharAt(path.length()-1);
}
}
}