首页 > 试题广场 >

集合的所有子集(二)

[编程题]集合的所有子集(二)
  • 热度指数:3691 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个整数数组 nums ,其中可能包含重复元素,请你返回这个数组的所有可能子集。

返回的答案中不能包含重复的子集,将答案按字典序进行排序。

数据范围:数组长度满足 ,数组中元素大小满足
示例1

输入

[1,2]

输出

[[],[1],[1,2],[2]]
示例2

输入

[1]

输出

[[],[1]]
要想答案按照字典序排列,我们要先对数组进行升序排列,然后再在这个有序数组上利用回溯法求子集。需要一个布尔数组来记录i位置的数是否已经被使用,从而达到去重的目的,当遇到相同的数时,如果前一个相同的数已经回溯过,那当前这个数就可以不考虑了。
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型二维数组
     */
    ArrayList<ArrayList<Integer>> results = new ArrayList<>();
    public ArrayList<ArrayList<Integer>> subsets (int[] nums) {
        // write code here
        Arrays.sort(nums);
        boolean[] used = new boolean[nums.length];
        dfs(nums, 0, new ArrayList<Integer>(), used);
        return results;
    }
    
    private void dfs(int[] nums, int depth, ArrayList<Integer> result, boolean[] used) {
        results.add(new ArrayList<Integer>(result));
        for(int i = depth; i < nums.length; i++){
            if(i > 0 && nums[i - 1] == nums[i] && !used[i - 1]) continue;    // 上一个相同的数已经回溯过了,跳过
            result.add(nums[i]);
            used[i] = true;
            dfs(nums, i + 1, result, used);
            result.remove(result.size() - 1);
            used[i] = false;      // 回溯完后状态会被改成false
        }
    }
}

发表于 2021-12-11 10:25:33 回复(0)
这道题结果按照字典序输出明显考察回溯算法,如下给出较难一些的位运算解法,使用 0,1 代表当前位置元素是否选择,更符合程序员思想,结果使用优先队列来降低排序复杂度
public static ArrayList<ArrayList<Integer>> subsets(int[] nums) {
         // write code here
        Arrays.sort(nums); // 元素位置可颠倒
        int subLen = (int) Math.pow(2, nums.length);
        PriorityQueue<ArrayList<Integer>> priorityQueue = new PriorityQueue<>(
            (o1, o2) -> {
            StringBuilder o1Sb = new StringBuilder();
            StringBuilder o2Sb = new StringBuilder();
            for (Integer o1e : o1) o1Sb.append(o1e);
            for (Integer o2e : o2) o2Sb.append(o2e);
            return o1Sb.toString().compareTo(o2Sb.toString());
        });
        for (int i = 0; i < subLen; i++) {
            String s = Integer.toBinaryString(i);
            ArrayList<Integer> subList = new ArrayList<>();
            for (int j = 0; j < s.length(); j++)
                if (s.charAt(s.length() - j - 1) == '1')
                    subList.add(nums[j]);
            priorityQueue.add(subList);
        }
 
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        while (!priorityQueue.isEmpty()) {
            ArrayList<Integer> poll = priorityQueue.poll();
            if (!res.isEmpty() && res.get(res.size() - 1).equals(poll))
                continue;
            res.add(poll);
        }
        return res;
    }

解法二:常规暴力递归回溯,注意组装结果时直接就按照字典序来组装
 public static ArrayList<ArrayList<Integer>> subsetsTraceback(int[] nums) {
        Arrays.sort(nums);// 排序是因为题目需要字典序顺序
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        res.add(new ArrayList<>());// 空集合
        helper(nums, 0, res, new ArrayList<>());
        return res;
    }

    public static void helper(int[] nums, int pos, 
                              ArrayList<ArrayList<Integer>> res, List<Integer> cur) {
        for (int i = pos; i < nums.length; i++) {
            cur.add(nums[i]); // 为了字典序, 先加入再递归
            if (!res.contains(cur)){ // 递归和回溯时不同深度栈帧和不同i会有大量重复,需判断去重
                res.add(new ArrayList<>(cur));// 先把当前子集加入结果集
                helper(nums, i + 1, res, cur); // 继续找比当前大的字典序子集
            }
            cur.remove(cur.size() - 1);//当前的元素处理完毕,尝试其他, 回溯
        }
    }
总结: 位运算稍难,回溯符合大众,但仍需熟练才能信手拈来

发表于 2024-09-10 12:05:02 回复(0)
使用位运算枚举的解法
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param nums int整型一维数组 
# @return int整型二维数组
#
class Solution:
    def subsets(self , nums: List[int]) -> List[List[int]]:
        # write code here
        s = set()
        nums.sort()

        count = pow(2, len(nums))
        for i in range(count):
            b = bin(i)[2:]
            
            tmp = []
            for j in range(len(nums)-len(b), len(nums)):
                if b[j-(len(nums)-len(b))] == '1':
                    tmp.append(nums[j])

            s.add(tuple(tmp))

        res = list(s)
        res.sort()

        return res


发表于 2024-04-17 22:39:10 回复(0)
    vector<vector<int> > subsets(vector<int>& nums) {
        // write code here
        set<vector<int>> res = {{}};  // 初始包含空集
        for (int num : nums) {
            set<vector<int>> temp = res;  // 复制当前所有子集
            for (auto subset : temp) {      // 遍历每个已有子集
                subset.push_back(num);       // 添加当前元素
                sort(subset.begin(), subset.end());
                res.insert(subset);       // 添加新生成的子集
            }
        }
        vector<vector<int>> result;
        for (auto r : res) {
            result.push_back(r);
        }
        return result;
    }

发表于 2025-06-28 15:14:42 回复(0)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型ArrayList<ArrayList<>>
     */
    ArrayList<ArrayList<Integer>> res = new ArrayList<>();
    ArrayList<Integer> path = new ArrayList<>();

    public ArrayList<ArrayList<Integer>> subsets (int[] nums) {
        // write code here
        // 回溯
        Arrays.sort(nums);
        backtracing(0, nums);
        return res;
    }

    private void backtracing(int start, int[] nums) {
        res.add(new ArrayList<>(path));

        for(int i = start; i < nums.length; i++) {
            // 层内去重
            if((i != start) && (nums[i] == nums[i - 1])) continue;
            path.add(nums[i]);
            backtracing(i + 1, nums);
            path.remove(path.size() - 1);
        }
    }
}

编辑于 2024-02-10 14:37:17 回复(0)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型ArrayList<ArrayList<>>
     */
     ArrayList<ArrayList<Integer>> result=new ArrayList<>();
    LinkedList<Integer> path=new LinkedList<>();
    public ArrayList<ArrayList<Integer>> subsets (int[] nums) {
        // write code here
        Arrays.sort(nums);
        backtracking(nums,0);
        return result;
    }
    void backtracking(int[] nums,int start){
        result.add(new ArrayList<>(path));
        for(int i=start;i<nums.length;i++){
            if(i>start&&nums[i-1]==nums[i])continue;
            path.add(nums[i]);
            backtracking(nums,i+1);
            path.removeLast();
        }
    }
}

编辑于 2024-01-29 15:44:28 回复(0)
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型ArrayList<ArrayList<>>
     */
    private ArrayList<ArrayList<Integer>>  result = new ArrayList<>();
    private Deque<Integer> path = new LinkedList<>();

    public ArrayList<ArrayList<Integer>> subsets (int[] nums) {
        Arrays.sort(nums);

        boolean[] used = new boolean[nums.length];
        backTracking(nums, 0, used);
        Collections.sort(result, new CustomComparator());
        return result;
    }

    private void backTracking(int[] nums, int index, boolean[] used) {
        result.add(new ArrayList<>(path));

        for (int i=index; i<nums.length; i++) {
            if (i > 0 && used[i-1] == false && nums[i] == nums[i-1]) continue;
            
            used[i] = true;
            path.offer(nums[i]);
            backTracking(nums, i+1, used);
            path.pollLast();
            used[i] = false;
        }
    }

    private static class CustomComparator implements Comparator<ArrayList<Integer>> {
        public int compare(ArrayList<Integer> a, ArrayList<Integer> b) {
            //if (a.isEmpty()) return 1;
            //if (b.isEmpty()) return -1;

            StringBuilder str1 = new StringBuilder();
            StringBuilder str2 = new StringBuilder();
            for (int e: a) str1.append(e);
            for (int e: b) str2.append(e);

            return str1.toString().compareTo(str2.toString());
        }
    }
}

发表于 2023-08-26 11:57:44 回复(0)
package main
import "sort"

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param nums int整型一维数组 
 * @return int整型二维数组
*/
func subsets( nums []int ) [][]int {
    sort.Ints(nums)
    ans:=[][]int{}
    var dfs func([]int,int)
    dfs=func(path []int,idx int){
        tmp:=make([]int,len(path))
        copy(tmp,path)
        ans=append(ans,tmp)
        for i:=idx;i<len(nums);i++{
            if i>idx&&nums[i]==nums[i-1]{
                continue
            }
            path=append(path,nums[i])
            dfs(path,i+1)
            path=path[:len(path)-1]
        }
    }
    dfs([]int{},0)
    return ans
}

发表于 2023-03-10 21:37:22 回复(0)
# -*- coding: utf-8 -*-

#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param nums int整型一维数组
# @return int整型二维数组
#
class Solution:
    """
    题目:
        集合的所有子集(二)
        https://www.nowcoder.com/practice/a3dfd4bc8ae74fad9bc65d5ced7ae813?tpId=117&&tqId=39446&rp=1&ru=/ta/job-code-high&qru=/ta/job-code-high/question-ranking
    参考:
        大神:代码界的小白
        https://leetcode.cn/problems/sliding-window-median/solution/hua-dong-chuang-kou-zhong-wei-shu-by-lee-7ai6/
    算法:
        题目要求:寻找nums的所有子集,结果按字典序排序
        1. 对nums进行排序
        2. 定义回溯函数dfs(combine, idx),初始combine为[],idx为0。
            a. 记录子集combine
            b. 枚举可选元素,加入combine,从下一个下标继续搜索;搜索完毕,回溯
    复杂度:
        时间复杂度:O(nlogn + n * 2^n) = O(n * 2^n),排序算法的复杂度:O(nlogn),构造子集:共2^n种状态,每种状态需要O(n)复杂度构造子集,构造子集的总复杂度为O(n * 2^n)
        空间复杂度:O(n),临时数组combine
    """

    def subsets(self, nums):
        # write code here
        def dfs(combine, idx):
            res.append(combine[:])
            for i in range(idx, n):
                if i > idx and nums[i] == nums[i - 1]: # 剪枝:前一个相同的数已经回溯了
                    continue
                combine.append(nums[i])
                dfs(combine, i + 1)
                combine.pop()

        nums.sort()
        res, n = [], len(nums)

        dfs([], 0)

        return res


if __name__ == '__main__':
    s = Solution()

    # nums = [1, 2]

    # nums = [1]

    nums = [1, 1, 1]

    # nums = [3, 6, 7, 5]

    res = s.subsets(nums)

    print res

发表于 2022-07-06 14:52:07 回复(0)
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param nums int整型一维数组 
 * @return int整型二维数组
 */
let result=[],path=[],visited=[];
function subsets( nums ) {
    // write code here
    nums.sort(function(a,b){
        return a-b;
    })
    backTrace(nums,nums.length,0);
    return result;
}
function backTrace(n,k,start){
    result.push([...path]);
    for(let i=start;i<k;i++){
        // 增加访问标记visited,避免[1,1,1] 重复元素重复添加
        if(i>start && n[i]==n[i-1]) continue; // 满足条件继续
        // if(i > 0 && n[i]==n[i-1] && !visited[i-1]) continue;
        path.push(n[i]);
       // visited[i]=1; // 节点被访问
        backTrace(n,k,i+1);
        path.pop();
       // visited[i]=0; // 节点访问标记置0
    }
}
module.exports = {
    subsets : subsets
};
发表于 2022-04-24 12:15:35 回复(0)
class Solution:
    def subsets(self , nums: List[int]) -> List[List[int]]:
        # write code here
        if len(nums)<=1:
            return [nums]
        res=[]
        nums.sort()
        def backtrace(start,path):
            res.append(path)
            add=set()
            for i in range(start,len(nums)):
                if nums[i] not in add:
                    add.add(nums[i])
                    cur_path=path+[nums[i]]
                    backtrace(1+i, cur_path)
        backtrace(0,[])
        #res.sort()
        return res

编辑于 2022-04-12 07:06:53 回复(0)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型二维数组
     */
    ArrayList<ArrayList<Integer>> ans = new ArrayList<ArrayList<Integer>>();
    //HashSet<ArrayList<Integer>> set = new HashSet<ArrayList<Integer>>();
    public ArrayList<ArrayList<Integer>> subsets (int[] nums) {
        // write code here
        ArrayList<Integer> list = new ArrayList<>();
        //ans.add(list);
        Arrays.sort(nums);
        dfs(nums, 0, list);
        return ans;
    }
    
    public void dfs(int[] nums, int start, ArrayList<Integer> list){
        if(!ans.contains(list)){
            ans.add(new ArrayList<Integer>(list));
        }
        for(int i=start;i<nums.length;i++){
            list.add(nums[i]);
            dfs(nums, i+1, list);
            list.remove(list.size()-1);
        }
    }
}


发表于 2021-12-07 10:49:19 回复(0)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型二维数组
     */
    ArrayList<ArrayList<Integer>> ans = new ArrayList<>();
    List<Integer> list = new LinkedList<>();
    
    public ArrayList<ArrayList<Integer>> subsets (int[] nums) {
        // write code here
        Arrays.sort(nums);
        dfs(nums,0);
        return ans;
    }
    void dfs(int[] nums, int index){
        
        ans.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]);
            dfs(nums,i+1);
            list.remove(list.size() - 1);
        }
    }
}

发表于 2021-12-03 20:16:40 回复(0)

问题信息

难度:
13条回答 4392浏览

热门推荐

通过挑战的用户

查看代码
集合的所有子集(二)