首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

LeetCode 78 Subsets:位掩碼枚舉與回溯生成所有子集

     編輯:關於C++

問題描述

給定一個無重複元素的整數數組 nums,返回所有可能的子集(冪集)。子集內元素非降序,解集無重複。

示例:nums = [1,2,3] → [[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]

方法一:位掩碼枚舉(最直觀)

n 個元素共有 2^n 個子集。整數 0 ~ 2^n-1 的二進制位完美對應「選/不選」:

public List> subsets(int[] nums) {
    List> res = new ArrayList<>();
    int n = nums.length;
    for (int mask = 0; mask < (1< subset = new ArrayList<>();
        for (int i = 0; i < n; ++i)
            if ((mask & (1<
  • 無需排序(題目保證無重複),但輸出要求非降序,建議先 Arrays.sort(nums)。
  • 時間:O(n·2^n),空間:O(n·2^n)(輸出佔主導)。

方法二:回溯法(標準 DFS)

public List> subsets(int[] nums) {
    Arrays.sort(nums);
    List> res = new ArrayList<>();
    backtrack(nums, 0, new ArrayList<>(), res);
    return res;
}

void backtrack(int[] nums, int start, List path, List> res) {
    res.add(new ArrayList<>(path));
    for (int i = start; i < nums.length; ++i) {
        path.add(nums[i]);
        backtrack(nums, i+1, path, res);
        path.remove(path.size()-1);
    }
}

遞歸樹清晰展示「選/不選」決策,易於擴展到組合總和、排列等問題。

方法三:迭代增量構建(空間最優)

public List> subsets(int[] nums) {
    List> res = new ArrayList<>();
    res.add(new ArrayList<>());
    for (int num : nums) {
        int size = res.size();
        for (int i = 0; i < size; ++i) {
            List cur = new ArrayList<>(res.get(i));
            cur.add(num);
            res.add(cur);
        }
    }
    return res;
}

每輪將新元素加入現有所有子集,生成新子集。無遞歸棧開銷。

三種方法對比

維度位掩碼回溯迭代
思維直觀度★★★★★☆★★☆
代碼簡潔度★★★★★☆★★★
擴展性差強(易加剪枝)中
空間(輔助)O(1)O(n)O(1)

總結

Subsets I 是子集問題的入門題。位掩碼適合快速寫出正確解;回溯是面試標準解法,便於舉一反三;迭代空間效率最高。建議三種都會寫,並理解它們本質上都是遍歷 {0,1}^n 空間。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved