Open azl397985856 opened 2 years ago
题意: 数组中的元素互不相同.
在二进制状态下做状态的轮流变换(1表示选中, 0表示不选中).
实现语言: C++
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
const int n = nums.size();
vector<vector<int>> res;
for (int s = 0; s < (1 << n); s++)
{ /* s表示一个状态state, 共有2^n (1 << n)个状态 */
vector<int> curSet;
for (int i = 0; i < n; i++)
if ((s & (1 << i)) > 0) /* 从末位开始, 循环判断当前位是不是1. 注意位运算的优先级不比+、>、<、=高, 可以加括号后判断>0, 也可以简写为 if (s & (1 << i)) */
curSet.push_back(nums[i]);
res.push_back(curSet);
}
return res;
}
};
class Solution {
List<Integer> t = new ArrayList<Integer>();
List<List<Integer>> ans = new ArrayList<List<Integer>>();
public List<List<Integer>> subsets(int[] nums) {
int n = nums.length;
for (int mask = 0; mask < (1 << n); ++mask) {
t.clear();
for (int i = 0; i < n; ++i) {
if ((mask & (1 << i)) != 0) {
t.add(nums[i]);
}
}
ans.add(new ArrayList<Integer>(t));
}
return ans;
}
}
让k从0到2^n-1次方进行遍历,这样k的某一个bit为1,那么对应的nums中的数就应该放进去, 这样就能遍历所有的subset
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
"""
iterative
"""
end_num = 2 ** len(nums)
results = []
for k in range(end_num):
single_solution = []
for i in range(len(nums)):
if (k >> i) & 1 == 1:
single_solution.append(nums[i])
results.append(single_solution)
return results
Time O(2^n*n)
Space O(2^n*n))
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
'''
注意 path 添加的必须是深拷贝,以免后面答案添加之后影响到 res 中的 path
'''
res = []
path = []
def backtrack(nums, path, start):
# 注意:其实 nums 这个参数不带也行,从头到尾我们也没修改过 nums
res.append(path[:])
for i in range(start, len(nums)):
path.append(nums[i])
backtrack(nums, path, i+1)
path.pop()
backtrack(nums, path, 0)
return res
'''
method 2
'''
res = [[]]
for num in nums:
res += [cur + [num] for cur in res]
return res
'''
method 3 bit manipulation
每个元素有两种状态,拿或者不拿,那么如果一共有NN个数,那就一共有 2^N 种可能,也就是有这么多个子集(子集包括全集和空集)。
既然每一个数只有两种状态,那么我们不妨用一个 bit 来表示。这样题中的[1,2,3],我们可以看成一个三个比特的组合:
比如 0 0 0 就代表空集,1 1 1 就代表全集, 1 0 0 就代表[1] (可正可反)。
这样我们就可以进行位操作,0 - 2^n - 1的数的二进制数位为 1 的位置,就把对应的元素填入集合中。
PS: ((1 << i )& sign) != 0 的意思是用第 i 位是 1 比特与当前 sign 相与,若结果不为 0 就代表 第 i 位 比是 1
time: O(N * 2^N)
space: O(N)
'''
# 1 << len(nums) means 2 ** len(nums)
res, end = [], 1 << len(nums)
for sign in range(end):
subset = []
for i in range(len(nums)):
if ((1 << i) & sign) != 0:
subset.append(nums[i])
res.append(subset)
return res
class Solution {
List<List<Integer>> res;
public List<List<Integer>> subsets(int[] nums) {
res = new ArrayList();
dfs(nums, 0, new ArrayList());
return res;
}
private void dfs(int[] nums, int index, List<Integer> path) {
res.add(new ArrayList(path));
for (int i = index; i < nums.length; i++) {
path.add(nums[i]);
dfs(nums, i + 1, path);
path.remove(path.size() - 1);
}
}
}
public List<List<Integer>> subsets(int[] nums) {
int n = nums.length;
List<List<Integer>> res = new ArrayList();
for (int state = 0; state < (1 << n); state++) {
List<Integer> path = new ArrayList();
for (int i = 0; i < n; i++) {
if (((state >> i) & 1) != 0) {
path.add(nums[i]);
}
}
res.add(path);
}
return res;
}
C++ Code:
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<int> onePath;
vector<vector<int>> ret;
backTrac(nums, 0, onePath, ret);
return ret;
}
void backTrac(vector<int>& nums, int start, vector<int>& onePath, vector<vector<int>>& ret)
{
// if(start>= nums.size())
// return;
ret.push_back(onePath);
for(int i= start; i< nums.size(); i++)
{
onePath.push_back(nums[i]);
backTrac(nums, i+1, onePath, ret);
onePath.pop_back();
}
}
};
bitmask上瘾
能写一行绝不写两行
def subsets(self, nums: List[int]) -> List[List[int]]:
return [[nums[j] for j in range(len(nums)) if (1<<j)&i]for i in range(1<<len(nums))]
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
if nums is None:
return []
nums.sort()
result = []
self.dfs(nums, result, 0, [])
return result
def dfs(self, nums, result, index, path):
result.append(list(path))
for i in range(index, len(nums)):
path.append(nums[i])
self.dfs(nums, result, i + 1, path)
path.pop()
Backtracking
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> each = new ArrayList<>();
helper(res, each, 1, n, k);
return res;
}
public void helper(List<List<Integer>> res, List<Integer> each, int pos, int n, int k) {
if (each.size() == k) {
res.add(each);
return;
}
for (int i = pos; i <= n; i++) {
each.add(i);
helper(res, new ArrayList<>(each), i + 1, n, k);
each.remove(each.size() - 1);
}
return;
}
空间复杂度: O(N)
时间复杂度: O(N×2^N)
Date: 2021-11-19
Key Insights
Complexity: O(2^n); O(2^n)
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
N = len(nums)
def dfs(idx, path):
if idx == N:
nonlocal result
result.append(path)
return
dfs(idx+1, path+[nums[idx]])
dfs(idx+1, path)
def bt(idx, path):
nonlocal result
result.append(list(path))
for i in range(idx, N):
path.append(nums[i])
bt(i+1, path)
path.pop()
result = []
bt(0, [])
return result
const subsets = (nums) => {
const n = nums.length;
const ans = [];
if (n < 1) return [[]];
const dfs = (i, curr) => {
ans.push([...curr]);
for (let idx=i;idx<n;idx++) {
curr.push(nums[idx]);
dfs(idx+1, curr);
curr.pop();}};
dfs(0, []);
return ans;
};
class Solution(object):
def subsets(self, nums):
result = []
if len(nums)==0:
return result
def dfs(index, cur):
result.append(deepcopy(cur))
for i in range(index, len(nums)):
cur.append(nums[i])
dfs(i+1, cur)
cur.remove(nums[i])
dfs(0, [])
return result
class Solution(object): def subsets(self, nums): if len(nums) == 0: return [] result = [] seen = set([]) def backtracking(cur, index): if index == len(nums): if tuple(cur) not in seen: result.append(cur) else: copy = deepcopy(cur) if tuple(copy) not in seen: result.append(copy) seen.add(tuple(copy)) backtracking(cur+[nums[index]], index+1) backtracking(cur, index+1) backtracking([nums[0]], 1) backtracking([], 1) return result```
class Solution
{
public:
vector<vector<int>> subsets(vector<int> &nums)
{
// nums.length <= 10
// use a 2-bytes short as a hashtable to mark if a subset has been seen before or not
// a table of encoded vector of indices from the nums
std::unordered_set<short> table;
// backtrack helper variable to mark if num has been visted or not
std::vector<bool> visited(nums.size(), false);
std::vector<int> subvec;
std::vector<std::vector<int>> res;
backtrack(nums.size(), subvec, visited, table, res);
// convert the indices into nums
for (auto &subset : res) {
for (auto &item : subset) {
item = nums[item];
}
}
return res;
}
private:
void backtrack(int n, std::vector<int> &subvec, std::vector<bool> &visited, std::unordered_set<short> &table,
std::vector<std::vector<int>> &res)
{
// serialize the subvec into a 2-bytes short
short subvecCode = serialize(subvec);
if (!table.count(subvecCode)) {
table.emplace(subvecCode);
res.emplace_back(subvec);
}
for (int ii = 0; ii < n; ii++) {
if (visited[ii]) continue;
visited[ii] = true;
subvec.push_back(ii);
backtrack(n, subvec, visited, table, res);
visited[ii] = false;
subvec.pop_back();
}
return;
}
inline short serialize(std::vector<int> &vec)
{
short code{ 0 };
for (auto const &idx : vec) {
code |= (1 << idx);
}
return code;
}
};
https://leetcode.com/problems/subsets/
Bit manipulation
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> curList = new ArrayList<>();
for(int mask = 0; mask < (1 << nums.length); mask++){
curList.clear();
for(int i = 0; i < nums.length; i++){
if((mask & (1 << i)) != 0){
curList.add(nums[i]);
}
}
res.add(new ArrayList<>(curList));
}
return res;
}
}
Backtrack
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> curList = new ArrayList<>();
helper(nums, 0, curList, res);
return res;
}
private void helper(int[] nums, int start, List<Integer> curList, List<List<Integer>> res){
if(start == nums.length){
res.add(new ArrayList<>(curList)); // deep copy
return;
}
// select the number at the current index
curList.add(nums[start]);
helper(nums, start + 1, curList, res);
// backtrack and not select the number at the current index
curList.remove(curList.size() - 1);
helper(nums, start + 1, curList, res);
}
}
题目要求枚举列表所有可能的子集,思路之一就是枚举,因为所有子集的个数为2^len(nums),所以i从0到2^len(nums),把i看作二进制解读,0表示该位没有数,1表示该位有数即可。
另一个思路类似,对于一个已经枚举了列表[1,2,3]所有子集的results而言,如果想再加上4,那么只用考虑所有已存在的results全部都带上4和全部都不带4两种情况即可;即[i + [num] for i in results]
是所有results带上了4,而不带4就是results本身,二者相加就是结果
class Solution:
def subsets1(self, nums: List[int]) -> List[List[int]]:
ans = []
for i in range(1 << len(nums)):
tmp = []
index = 0
while i:
if i & 1:
tmp.append(nums[index])
index += 1
i >>= 1
ans.append(tmp)
return ans
def subsets2(self, nums: List[int]) -> List[List[int]]:
return [[nums[j] for j in range(len(nums)) if 1 << j & i] for i in range(1 << len(nums))]
def subsets3(self, nums: List[int]) -> List[List[int]]:
results = [[]]
for num in nums:
results += [i + [num] for i in results]
return results
def subsets4(self, nums: List[int]) -> List[List[int]]:
return reduce(lambda res, num: res + [i + [num] for i in res], nums, [[]])
TC: O(2^n) SC: O(2^n)
Bitmask. A binary value to represent the element we choose in the subset (1 for choosing, 0 for not choosing).
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
s = 1<<len(nums)
ans = []
for i in range(s):
tmp = []
j = 0
for j in range(i>>j):
if i>>j & 1:
tmp.append(nums[j])
ans.append(tmp)
return ans
Time: O(N 2^N). Since the bitmask has N length, it has 2^N possible values. For each value from 2^N values, we need to right move N bits of the current value to check the selectd nums[i] Space: Time: O(N 2^N).
public List<List<Integer>> subsets(int[] nums) {
if (nums == null || nums.length == 0) {
return null;
}
List<List<Integer>> res = new ArrayList<>();
dfs(nums, 0, new ArrayList<>(), res);
return res;
}
private void dfs(int[] nums, int start, List<Integer> subset, List<List<Integer>> res) {
res.add(new ArrayList<>(subset));
for (int i = start; i < nums.length; i++) {
subset.add(nums[i]);
dfs(nums, i + 1, subset, res);
subset.remove(subset.size() - 1);
}
}
https://leetcode.com/problems/subsets/
const subsets = function(nums) {
let result = [[]];
function backtrack(first, current) {
for (let i = first; i < nums.length; i++) {
current.push(nums[i]);
result.push([...current]);
backtrack(i + 1, current);
current.pop();
}
}
backtrack(0, []);
return result
};
Java Code:
class Solution {
/**
* @param S: A set of numbers.
* @return: A list of lists. All valid subsets.
*/
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> results = new ArrayList<>();
if (nums == null) {
return results;
}
if (nums.length == 0) {
results.add(new ArrayList<Integer>());
return results;
}
Arrays.sort(nums);
helper(new ArrayList<Integer>(), nums, 0, results);
return results;
}
// 递归三要素
// 1. 递归的定义:在 Nums 中找到所有以 subset 开头的的集合,并放到 results
private void helper(ArrayList<Integer> subset,
int[] nums,
int startIndex,
List<List<Integer>> results) {
// 2. 递归的拆解
// deep copy
// results.add(subset);
results.add(new ArrayList<Integer>(subset));
for (int i = startIndex; i < nums.length; i++) {
// [1] -> [1,2]
subset.add(nums[i]);
// 寻找所有以 [1,2] 开头的集合,并扔到 results
helper(subset, nums, i + 1, results);
// [1,2] -> [1] 回溯
subset.remove(subset.size() - 1);
}
// 3. 递归的出口
return;
}
}
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if(nums == null || nums.length == 0) return res;
helper(res, new ArrayList<>(), nums, 0);
return res;
}
private void helper(List<List<Integer>> res, List<Integer> list, int[] nums, int idx) {
res.add(new ArrayList<>(list));
for(int i = idx; i < nums.length; i++) {
list.add(nums[i]);
helper(res, list, nums, i + 1);
list.remove(list.size() - 1);
}
}
}
O(2^n)
O(n)
# backtrack
# time: O(2^N)
# space: O(N)
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
res = []
self.backtrack(nums, res, [])
return res
def backtrack(self, nums, res, curr_list):
res.append(curr_list.copy())
if not nums:
return
for i, n in enumerate(nums):
curr_list.append(n)
self.backtrack(nums[i + 1:], res, curr_list)
curr_list.pop()
backtracking
使用语言:Python3:
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
def backtracking(index, curr):
if len(curr) == i:
sub.append(curr[:])
return
for j in range(index, n):
curr.append(nums[j])
backtracking(j + 1, curr)
curr.pop()
sub = []
n = len(nums)
curr = []
for i in range(n + 1):
backtracking(0, curr)
return sub
复杂度分析 时间复杂度:O(n* 2^n) 空间复杂度:O(n)
位运算,每个数字可以选也可以不选,所以子集最多有2^n个,所以枚举[0...2^n-1]的所有数字,用它们的二进制位作为选或者不选的标记,最后组成答案。
class Solution {
public List<List<Integer>> subsets(int[] nums) {
int size = 1 << nums.length;
List<List<Integer>> ans = new ArrayList<>();
for (int i=0; i<size; i++) {
List<Integer> subset = new ArrayList<>();
for (int j=0; j<nums.length; j++) {
if (((i >> j) & 1) == 1) {
subset.add(nums[j]);
}
}
ans.add(subset);
}
return ans;
}
}
TC: O(n * 2^n) SC: O(2^n)
思路: 啊!啊!啊! 前几天做过,今天思路又忘记了。 回顾: dfs深度搜索,每次都 copy添加到输出out里面, 从起始节点开始遍历,list加元素,可加可不加,加了做一次dfs,出来之后再去掉
func subsets(nums []int) [][]int {
out := [][]int{}
var dfs func(start int, list []int)
dfs = func(start int,list []int){
p := make([]int,len(list))
copy(p,list)
out = append(out,p)
for j:=start;j<len(nums);j++{
list = append(list,nums[j])
dfs(j+1,list)
list = list[:len(list)-1]
}
}
dfs(0,[]int{})
return out
}
时间复杂度O(n*2^n) 空间复杂度O(n)
var subsets = function (nums) {
let result = [];
let path = [];
function backtracking(startIndex) {
result.push(path.slice());
for (let i = startIndex; i < nums.length; i++) {
path.push(nums[i]);
backtracking(i + 1);
path.pop();
}
}
backtracking(0);
return result;
};
Recursion
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
helper(nums, new ArrayList<>(),0);
return res;
}
public void helper(int[] nums, List<Integer> cur, int index) {
res.add(new ArrayList<>(cur));
for (int i = index; i < nums.length; i++) {
cur.add(nums[i]);
helper(nums,cur,i+1);
cur.remove(cur.size()-1);
}
}
}
Time O(2^n*n)
Space O(2^n*n))
回溯算法
``
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
backtrack(0, nums, res, new ArrayList<Integer>());
return res;
}
private void backtrack(int i, int[] nums, List<List<Integer>> res, ArrayList<Integer> tmp) {
res.add(new ArrayList<>(tmp));
for (int j = i; j < nums.length; j++) {
tmp.add(nums[j]);
backtrack(j + 1, nums, res, tmp);
tmp.remove(tmp.size() - 1);
}
}
}
时间复杂度:O(2^n)
空间复杂度:O(n)
title: "Day 72 78. 子集" date: 2021-11-20T09:08:01+08:00 tags: ["Leetcode", "c++", "traceback"] categories: ["91-day-algorithm"] draft: true
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = [0]
输出:[[],[0]]
提示:
1 <= nums.length <= 10
-10 <= nums[i] <= 10
nums 中的所有元素 互不相同
- 1、本题目若是求子集个数该多好,直接全排列即可,可惜是求每一个对应的子集。
- 2、利用两个数组,一个存最后的答案,一个用来做缓存数组,两个dfs的意思为,先加入所有的子元素,然后一个一个剔除,剔除一个元素,最终的答案数组将其存入。
- 3、最后34天要考研了,写的会比较紧张。
class Solution {
public:
vector<int> tmp;
vector<vector<int>> ans;
vector<vector<int>> subsets(vector<int>& nums) {
dfs(0, nums);
return ans;
}
void dfs(int i, vector<int>& nums) {
int n = nums.size();
if (i == n) {
ans.push_back(tmp);
return;
}
tmp.push_back(nums[i]);
dfs(i + 1, nums);
tmp.pop_back();
dfs(i + 1, nums);
}
};
时间复杂度:O(n*2^n)
空间复杂度:O(n)
AC
//回溯
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
for(int i = 0;i <= nums.length;i++){
List<Integer> subset = new ArrayList<>();
backtrack(nums, i, subset, 0);
}
return res;
}
public boolean backtrack(int[] nums, int size, List<Integer> subset, int start){
if(subset.size() == size){
res.add(new ArrayList(subset));
return true;
}
for(int i = start;i < nums.length;i++){
subset.add(nums[i]);
backtrack(nums, size, subset, i+1);
subset.remove(subset.size() - 1);
}
return false;
}
}
//bit操作很神奇
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
int start = 0, end = (int)Math.pow(2, nums.length);
for(int sign = start;sign < end;sign++){
List<Integer> set = new ArrayList<>();
for(int i = 0;i < nums.length;i++){
if(((1 << i) & sign) != 0){
set.add(nums[i]);
}
}
res.add(set);
}
return res;
}
}
time: O(N * 2^N) space: O(N)
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
List<Integer> path = new ArrayList<Integer>();
search(nums, res, path, 0);
return res;
}
public void search(int[] nums, List<List<Integer>> res, List<Integer> path, int index) {
res.add(new ArrayList<>(path));
for (int i = index; i < nums.length; i++) {
path.add(nums[i]);
search(nums, res, path, i + 1);
path.remove(path.size() - 1);
}
}
}
https://leetcode-cn.com/problems/subsets/
bitManipulation
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
# time n * 2**n
# space n
res = []
sum = 1 << len(nums)
# 2**n
for i in range(0, sum):
tmp = []
# n
for j in range(0, len(nums)):
if (( i >> j ) & 1) == 1:
tmp.append(nums[j])
res.append(tmp)
return res
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
res = [[]]
for i in nums:
res += [[i] + num for num in res]
return res
Time: O(n)
Space: O(n^2)
class Solution:
def subsets(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
res, end = [], 1 << len(nums)
for sign in range(end):
subset = []
for i in range(len(nums)):
if ((1 << i) & sign) != 0:
subset.append(nums[i])
res.append(subset)
return res
class Solution(object):
def subsets(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
def helper(nums, i, cur, res):
if i >= len(nums):
res.append(cur)
return
helper(nums, i+1, cur+[nums[i]], res)
helper(nums, i+1, cur, res)
res = []
helper(nums, 0, [], res)
return res
Each num can be selected or unselected. So we can use a binary bitmask to map which number is selected.
Time: O(2^n * n) Space: O(2^n * n)
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
int n = nums.length;
for(int sign=0;sign<(1<<n);sign++) {
List<Integer> temp = new ArrayList<>();
for(int i=0;i<n;i++) {
if((sign&(1<<i))!=0) {
temp.add(nums[i]);
}
}
res.add(temp);
}
return res;
}
}
Iterative methods time(N^2)
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
res = [[]]
for i in range(len(nums)):
res += [[nums[i]]+j for j in res]
return res
遍历所有可能性 [0, 1<<l - 1]
每次如果 i & (1<<j) 代表这一位的 i 是 1, 那么这个 list 要取这一位数, 将这一位数添加到现在都 list tmp 中
遍历结束后将 tmp 加入 res 数组中
最后返回 res 数组
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
res = []
l = len(nums)
for i in range(1<<l):
tmp = []
for j in range(l):
if i & (1<<j):
tmp.append(nums[j])
res.append(tmp)
return res
时间复杂度: O(n * 2^n) 一共 2^n 个不同的状态, 每次构造一个状态的复杂度是 O(n)
空间复杂度: O(n) 每次 tmp 数组的空间复杂度是 O(n)
使用BFS,每次把一位加入到所有的已有list
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
result = [[]]
for num in nums:
for i in range(len(result)):
temp = result[i][:]
temp.append(num)
result.append(temp)
return result
时间复杂度: O(N*2^N)
空间复杂度: O(N)
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new LinkedList<>();
LinkedList<LinkedList<Integer>> dq = new LinkedList<>();
LinkedList<Integer> ls = new LinkedList<>();
HashMap<Integer,Integer> map = new HashMap<>();
for(int i=0 ;i < nums.length ;i++){
map.put(nums[i],i);
}
dq.offer(ls);
while(!dq.isEmpty()){
LinkedList<Integer> ol = dq.poll();
res.add(ol);
for(int i = ol.size()==0 ? 0 : map.get(ol.getLast())+1; i < nums.length; i++){
LinkedList<Integer> list = new LinkedList<>(ol);
list.add(nums[i]);
dq.offer(list);
}
}
return res;
}
}
不会回溯解法
var subsets = function(nums) {
const result = [[]]
for (const x of nums) {
result.push(...result.map(subset => subset.concat([x])))
}
return result
};
https://leetcode.com/problems/subsets/
backtracking
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
def backtrack(k, first = 0, curr = []):
nonlocal n, output
# if the combination is done
if len(curr) == k:
output.append(curr[:])
return
for i in range(first, n):
# add nums[i] into the current combination
curr.append(nums[i])
# use next integers to complete the combination
backtrack(k, i + 1, curr)
# backtrack
curr.pop()
output = []
n = len(nums)
for k in range(n + 1):
backtrack(k=k, first=0, curr=[])
return output
DP 时间复杂度: O(NLogN) 空间复杂度:O(N)
假设有N个元素,则有2^N种状态,每个状态可用1bit表示。
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
int n = nums.length;
for (int i = 0; i < (1 << n); i++){
List<Integer> list = new ArrayList<>();
for (int j = 0; j < n; j++){
if (((1 << j) & i) != 0){
list.add(nums[j]);
}
}
res.add(list);
}
return res;
}
}
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
res = [[]]
for num in nums:
for i in range(len(res)):
res.append(res[i] + [num])
return res
Space: O(1) Time: O(n * 2^n)
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
int n = nums.size();
vector<int> t;
vector<vector<int>> res;
for (int i = 0; i < (1 << n); ++i) {
t.clear();
for (int j = 0; j < n; ++j) {
if (i & (1 << j)) {
t.push_back(nums[j]);
}
}
res.push_back(t);
}
return res;
}
};
时间复杂度:O(N^2*N)
空间复杂度:O(N)
var subsets = function(nums) {
const ans = [];
const n = nums.length;
for (let mask = 0; mask < (1 << n); ++mask) {
const t = [];
for (let i = 0; i < n; ++i) {
if (mask & (1 << i)) {
t.push(nums[i]);
}
}
ans.push(t);
}
return ans;
};
代码(C++):
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res(1);
for (int num : nums) {
int len = res.size();
for (int i = 0; i < len; ++i) {
res.push_back(res[i]);
res.back().push_back(num);
}
}
return res;
}
};
位运算。长度为n的无重复元素数组的所有子集数为2^n
。我们可以用0
到2^n - 1
的二进制形式来表示不同子集。每一个二进制数从低位到高位分别表示nums[0]
到nums[n - 1]
在子集中的情况,我们检查对应数位是否为1,如果为1则放到子集中,最后返回子集的list即可。
class Solution {
public List<List<Integer>> subsets(int[] nums) {
int len = nums.length;
List<List<Integer>> res = new ArrayList<>();
// total number of all possible subsets is 2^len
for (int i = 0; i < (int) Math.pow(2, len); i++) {
// use a binary number to represent whether the number in this position
// is in the list
// check each digit and put the corresponding number in the result list
List<Integer> set = new ArrayList<>();
for (int j = 0; j < len; j++) {
// the digit in position j starting from LSD is 1
// meaning nums[j] is in the subset
if (((i >> j) & 1) == 1) {
set.add(nums[j]);
}
}
res.add(set);
}
return res;
}
}
复杂度分析
Go Code:
func subsets(nums []int) [][]int {
var res [][]int
res = append(res, []int{})
var f func(int, []int)
f = func(start int, c []int) {
if start >= len(nums) {
return
}
for i:=start;i<len(nums);i++ {
c = append(c, nums[i])
tmp := make([]int, len(c))
copy(tmp, c)
res = append(res, tmp)
f(i+1, c)
c = c[:len(c)-1]
}
}
f(0, []int{})
return res
}
复杂度分析
令 n 为数组长度。
思路: backtracking
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
compose(result, new ArrayList<Integer>(), nums, 0);
return result;
}
private void compose(List<List<Integer>> result, List<Integer> list, int[] nums, int index) {
result.add(new ArrayList<>(list));
for (int i = index; i < nums.length; i++) {
list.add(nums[i]);
compose(result, list, nums, i + 1);
list.remove(list.size() - 1);
}
}
}
Time Complexity: O(2^n) Space Complexity: O(n)
位运算枚举
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<int>t;
vector<vector<int>>ans;
int n=nums.size(),max=(1<<n);
for(int i=0;i<max;++i){
t.clear();
for(int j=0;j<n;++j){
if((1<<j)&i){
t.push_back(nums[j]);
}
}
ans.push_back(t);
}
return ans;
}
};
复杂度分析
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
backtrack(0, nums, res, new ArrayList<Integer>());
return res;
}
private void backtrack(int i, int[] nums, List<List<Integer>> res, ArrayList<Integer> tmp) {
res.add(new ArrayList<>(tmp));
for (int j = i; j < nums.length; j++) {
tmp.add(nums[j]);
backtrack(j + 1, nums, res, tmp);
tmp.remove(tmp.size() - 1);
}
}
}
时间复杂度:O(N^2) 空间复杂度:O(N)
78. 子集
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/subsets/
前置知识
题目描述
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3] 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]] 示例 2:
输入:nums = [0] 输出:[[],[0]]
提示:
1 <= nums.length <= 10 -10 <= nums[i] <= 10 nums 中的所有元素 互不相同