列表

详情


90. 子集 II

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

 

示例 1:

输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

示例 2:

输入:nums = [0]
输出:[[],[0]]

 

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10

相似题目

子集

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: vector<vector<int>> subsetsWithDup(vector<int>& nums) { } };

rust 解法, 执行用时: 0 ms, 内存消耗: 2.4 MB, 提交时间: 2025-02-05 09:26:31

impl Solution {
    pub fn subsets_with_dup(mut nums: Vec<i32>) -> Vec<Vec<i32>> {
        nums.sort_unstable();

        fn dfs(mut i: usize, nums: &[i32], ans: &mut Vec<Vec<i32>>, path: &mut Vec<i32>) {
            if i == nums.len() {
                ans.push(path.clone());
                return;
            }

            // 选 x
            let x = nums[i];
            path.push(x);
            dfs(i + 1, nums, ans, path);
            path.pop(); // 恢复现场

            // 不选 x,那么后面所有等于 x 的数都不选
            // 如果不跳过这些数,会导致「选 x 不选 x'」和「不选 x 选 x'」这两种情况都会加到 ans 中,这就重复了
            i += 1;
            while i < nums.len() && nums[i] == x {
                i += 1;
            }
            dfs(i, nums, ans, path);
        }

        let mut ans = vec![];
        let mut path = vec![];
        dfs(0, &nums, &mut ans, &mut path);
        ans
    }

    // 枚举选哪个
    pub fn subsets_with_dup2(mut nums: Vec<i32>) -> Vec<Vec<i32>> {
        nums.sort_unstable();

        fn dfs(i: usize, nums: &[i32], ans: &mut Vec<Vec<i32>>, path: &mut Vec<i32>) {
            ans.push(path.clone());

            // 在 [i,n-1] 中选一个 nums[j]
            // 注意选 nums[j] 意味着 [i,j-1] 中的数都没有选
            for j in i..nums.len() {
                // 如果 j>i,说明 nums[j-1] 没有选
                // 同方法一,所有等于 nums[j-1] 的数都不选
                if j > i && nums[j] == nums[j - 1] {
                    continue;
                }
                path.push(nums[j]);
                dfs(j + 1, nums, ans, path);
                path.pop(); // 恢复现场
            }
        }

        let mut ans = vec![];
        let mut path = vec![];
        dfs(0, &nums, &mut ans, &mut path);
        ans
    }
}

javascript 解法, 执行用时: 2 ms, 内存消耗: 53.1 MB, 提交时间: 2025-02-05 09:25:46

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var subsetsWithDup1 = function(nums) {
    nums.sort((a, b) => a - b);
    const n = nums.length;
    const ans = [];
    const path = [];

    function dfs(i) {
        if (i === n) {
            ans.push([...path]);
            return;
        }

        // 选 x
        const x = nums[i];
        path.push(x);
        dfs(i + 1);
        path.pop(); // 恢复现场

        // 不选 x,那么后面所有等于 x 的数都不选
        // 如果不跳过这些数,会导致「选 x 不选 x'」和「不选 x 选 x'」这两种情况都会加到 ans 中,这就重复了
        i++;
        while (i < n && nums[i] === x) {
            i++;
        }
        dfs(i);
    }

    dfs(0);
    return ans;
};

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var subsetsWithDup = function(nums) {
    nums.sort((a, b) => a - b);
    const n = nums.length;
    const ans = [];
    const path = [];

    function dfs(i) {
        ans.push([...path]);

        // 在 [i,n-1] 中选一个 nums[j]
        // 注意选 nums[j] 意味着 [i,j-1] 中的数都没有选
        for (let j = i; j < n; j++) {
            // 如果 j>i,说明 nums[j-1] 没有选
            // 同方法一,所有等于 nums[j-1] 的数都不选
            if (j > i && nums[j] === nums[j - 1]) {
                continue;
            }
            path.push(nums[j]);
            dfs(j + 1);
            path.pop(); // 恢复现场
        }
    }

    dfs(0);
    return ans;
};

golang 解法, 执行用时: 0 ms, 内存消耗: 4.3 MB, 提交时间: 2025-02-05 09:22:52

func subsetsWithDup(nums []int) (ans [][]int) {
    slices.Sort(nums)
    n := len(nums)
    path := []int{}
    var dfs func(int)
    dfs = func(i int) {
        ans = append(ans, slices.Clone(path))

        // 在 [i,n-1] 中选一个 nums[j]
        // 注意选 nums[j] 意味着 [i,j-1] 中的数都没有选
        for j := i; j < n; j++ {
            // 如果 j>i,说明 nums[j-1] 没有选
            // 同方法一,所有等于 nums[j-1] 的数都不选
            if j > i && nums[j] == nums[j-1] {
                continue
            }
            path = append(path, nums[j])
            dfs(j + 1)
            path = path[:len(path)-1] // 恢复现场
        }
    }
    dfs(0)
    return ans
}

// 选或不选
func subsetsWithDup2(nums []int) (ans [][]int) {
    slices.Sort(nums)
    n := len(nums)
    path := []int{}
    var dfs func(int)
    dfs = func(i int) {
        if i == n {
            ans = append(ans, slices.Clone(path))
            return
        }

        // 选 x
        x := nums[i]
        path = append(path, x)
        dfs(i + 1)
        path = path[:len(path)-1] // 恢复现场

        // 不选 x,跳过所有等于 x 的数
        // 如果不跳过这些数,会导致「选 x 不选 x'」和「不选 x 选 x'」这两种情况都会加到 ans 中,这就重复了
        i++
        for i < n && nums[i] == x {
            i++
        }
        dfs(i)
    }
    dfs(0)
    return ans
}

cpp 解法, 执行用时: 0 ms, 内存消耗: 13.3 MB, 提交时间: 2025-02-05 09:21:54

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        ranges::sort(nums);
        int n = nums.size();
        vector<vector<int>> ans;
        vector<int> path;

        auto dfs = [&](this auto&& dfs, int i) -> void {
            if (i == n) {
                ans.push_back(path);
                return;
            }

            // 选 x
            int x = nums[i];
            path.push_back(x);
            dfs(i + 1);
            path.pop_back(); // 恢复现场

            // 不选 x,跳过所有等于 x 的数
            // 如果不跳过这些数,会导致「选 x 不选 x'」和「不选 x 选 x'」这两种情况都会加到 ans 中,这就重复了
            i++;
            while (i < n && nums[i] == x) {
                i++;
            }
            dfs(i);
        };

        dfs(0);
        return ans;
    }

    // 枚举选哪个
    vector<vector<int>> subsetsWithDup2(vector<int>& nums) {
        ranges::sort(nums);
        int n = nums.size();
        vector<vector<int>> ans;
        vector<int> path;

        auto dfs = [&](this auto&& dfs, int i) -> void {
            ans.push_back(path);

            // 在 [i,n-1] 中选一个 nums[j]
            // 注意选 nums[j] 意味着 [i,j-1] 中的数都没有选
            for (int j = i; j < n; j++) {
                // 如果 j>i,说明 nums[j-1] 没有选
                // 同方法一,所有等于 nums[j-1] 的数都不选
                if (j > i && nums[j] == nums[j - 1]) {
                    continue;
                }
                path.push_back(nums[j]);
                dfs(j + 1);
                path.pop_back(); // 恢复现场
            }
        };

        dfs(0);
        return ans;
    }
};

java 解法, 执行用时: 1 ms, 内存消耗: 42.6 MB, 提交时间: 2025-02-05 09:21:40

class Solution {
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> ans = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        dfs(0, nums, ans, path);
        return ans;
    }

    private void dfs(int i, int[] nums, List<List<Integer>> ans, List<Integer> path) {
        ans.add(new ArrayList<>(path));

        // 在 [i,n-1] 中选一个 nums[j]
        // 注意选 nums[j] 意味着 [i,j-1] 中的数都没有选
        for (int j = i; j < nums.length; j++) {
            // 如果 j>i,说明 nums[j-1] 没有选
            // 同方法一,所有等于 nums[j-1] 的数都不选
            if (j > i && nums[j] == nums[j - 1]) {
                continue;
            }
            path.add(nums[j]);
            dfs(j + 1, nums, ans, path);
            path.remove(path.size() - 1); // 恢复现场
        }
    }
}

java 解法, 执行用时: 1 ms, 内存消耗: 42.6 MB, 提交时间: 2025-02-05 09:21:24

class Solution {
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> ans = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        dfs(0, nums, ans, path);
        return ans;
    }

    private void dfs(int i, int[] nums, List<List<Integer>> ans, List<Integer> path) {
        int n = nums.length;
        if (i == n) {
            ans.add(new ArrayList<>(path));
            return;
        }

        // 选 x
        int x = nums[i];
        path.add(x);
        dfs(i + 1, nums, ans, path);
        path.remove(path.size() - 1); // 恢复现场

        // 不选 x,跳过所有等于 x 的数
        // 如果不跳过这些数,会导致「选 x 不选 x'」和「不选 x 选 x'」这两种情况都会加到 ans 中,这就重复了
        i++;
        while (i < n && nums[i] == x) {
            i++;
        }
        dfs(i, nums, ans, path);
    }
}

python3 解法, 执行用时: 0 ms, 内存消耗: 17.9 MB, 提交时间: 2025-02-05 09:19:55

class Solution:
    # 选或不选,先排序
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        n = len(nums)
        ans = []
        path = []

        def dfs(i: int) -> None:
            if i == n:
                ans.append(path.copy())  # 也可以写 path[:]
                return

            # 选 x
            x = nums[i]
            path.append(x)
            dfs(i + 1)
            path.pop()  # 恢复现场

            # 不选 x,那么后面所有等于 x 的数都不选
            # 如果不跳过这些数,会导致「选 x 不选 x'」和「不选 x 选 x'」这两种情况都会加到 ans 中,这就重复了
            i += 1
            while i < n and nums[i] == x:
                i += 1
            dfs(i)

        dfs(0)
        return ans
        
    # 枚举选哪个
    def subsetsWithDup2(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        n = len(nums)
        ans = []
        path = []

        def dfs(i: int) -> None:
            ans.append(path.copy())  # 也可以写 path[:]

            # 在 [i,n-1] 中选一个 nums[j]
            # 注意选 nums[j] 意味着 [i,j-1] 中的数都没有选
            for j in range(i, n):
                # 如果 j>i,说明 nums[j-1] 没有选
                # 同方法一,所有等于 nums[j-1] 的数都不选
                if j > i and nums[j] == nums[j - 1]:
                    continue
                path.append(nums[j])
                dfs(j + 1)
                path.pop()  # 恢复现场

        dfs(0)
        return ans

python3 解法, 执行用时: 40 ms, 内存消耗: 15.1 MB, 提交时间: 2022-11-24 10:54:31

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        res = []
        def back_tracking(temp, start):
            res.append(temp[:])
            for i in range(start, len(nums)):
                if i > start and nums[i] == nums[i-1]:
                    continue
                temp.append(nums[i])
                back_tracking(temp, i+1)
                temp.pop()
        back_tracking([], 0)
        return res

golang 解法, 执行用时: 0 ms, 内存消耗: 2.3 MB, 提交时间: 2022-11-24 10:53:46

// 递归法
func subsetsWithDup(nums []int) (ans [][]int) {
    sort.Ints(nums)
    t := []int{}
    var dfs func(bool, int)
    dfs = func(choosePre bool, cur int) {
        if cur == len(nums) {
            ans = append(ans, append([]int(nil), t...))
            return
        }
        dfs(false, cur+1)
        if !choosePre && cur > 0 && nums[cur-1] == nums[cur] {
            return
        }
        t = append(t, nums[cur])
        dfs(true, cur+1)
        t = t[:len(t)-1]
    }
    dfs(false, 0)
    return
}

golang 解法, 执行用时: 0 ms, 内存消耗: 2.5 MB, 提交时间: 2022-11-24 10:53:21

func subsetsWithDup(nums []int) (ans [][]int) {
    sort.Ints(nums)
    n := len(nums)
outer:
    for mask := 0; mask < 1<<n; mask++ {
        t := []int{}
        for i, v := range nums {
            if mask>>i&1 > 0 {
                if i > 0 && mask>>(i-1)&1 == 0 && v == nums[i-1] {
                    continue outer
                }
                t = append(t, v)
            }
        }
        ans = append(ans, append([]int(nil), t...))
    }
    return
}

上一题