LeetCode題解——78. 子集

題目相關

題目鏈接

LeetCode中國,https://leetcode-cn.com/problems/subsets/

題目描述

給定一組不含重複元素的整數數組 nums,返回該數組所有可能的子集(冪集)。

說明:解集不能包含重複的子集。

示例

輸入: nums = [1,2,3]
輸出:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

題目分析

LeetCode 給出本題難度中等。

題意分析

根據輸入的數列,生成所有的子集。很明顯,這是一個回溯算法題目。

方案1

樣例數據分析

本題的核心就是如何生成子集。也就是說利用回溯算法生成所有的子集。下面我們來分析一下樣例數據。樣例數據爲 [1, 2, 3],數列的長度爲 3,那麼我們的任務就是如何生成所有的子集。

我們可以考慮使用一個循環來生成子集。什麼意思呢,這個循環中,表示從第 i 個位置開始,到數列的結束,依次生成子集。循環代碼如下:

for (int i=pos; i<nums.size(); i++) {
    path.push_back(nums[i]);   //加入狀態
    dfs(nums, path, i+1);      //進一步搜索
    path.pop_back();           //回溯
}

下面我們用一張圖來說明一下對應的輸入數據的搜索過程:

從上圖,我們可以清晰的看到,如何從空集開始,逐步搜索的過程。

算法設計

參考輸入樣例數據分析。

搜索函數設計

設計搜索函數的核心就是確定要幾個參數。碰到這個問題,我們先不管三七二十一,將函數寫上去,然後再逐步確定需要幾個參數。這是寫回溯算法的套路。

1、一個數組,用來當前的所有數據集。

2、一個數組,用來當前的已經生成的子集。

3、一個整數,表示位置信息,即在所有數據集的索引。

這樣,我們就可以設計出一個帶有 3 個參數的搜索函數,原型如下。

void dfs(vector<int>& nums, vector<int> path, int pos);

搜索返回條件

這題的返回條件爲所有數據搜索完畢。

回溯

套路回溯即可,即套用回溯算法模板即可。

AC 參考代碼

class Solution {
public:
    vector<vector<int>> ans;

    /*
    參數1:
    參數2:
    參數3:從pos位置開始選
    */
    void dfs(vector<int>& nums, vector<int> path, int pos) {
        ans.push_back(path);

        for (int i=pos; i<nums.size(); i++) {
            path.push_back(nums[i]);
            dfs(nums, path, i+1);
            path.pop_back();
        }
    }

    vector<vector<int>> subsets(vector<int>& nums) {
        vector<int> path;
        dfs(nums, path, 0);
        
        return ans;
    }
};

方案 2

當然,我們還可以套用標準的回溯模板來實現。也就是搜索的方法不一樣,用一個比較容易理解的方法進行搜索,就是每次搜索按個數進行。第一次搜索所有 0 個數字子集,第二次搜索所有 1 個數字子集,第三次搜索所有 2 個數字字節,...,最後一次搜索所有 n 個數據子集。

樣例數據分析

這樣,我們可以繪製出對應的樣例數據搜索過程。

其他地方就不寫了,基本是雷同的。

AC 參考代碼

class Solution {
public:
    vector<vector<int>> ans;
    int n, k;

    /*
    參數1:
    參數2:
    參數3:從pos位置開始選
    */
    void dfs(vector<int>& nums, vector<int> path, int pos) {
        //退出條件
        if (path.size() == k) {
            //搜索到k個
            ans.push_back(path);
            return;
        }

        for (int i=pos; i<n; i++) {
            path.push_back(nums[i]);
            dfs(nums, path, i+1);
            path.pop_back();
        }
    }

    vector<vector<int>> subsets(vector<int>& nums) {
        n = nums.size();

        vector<int> path;
        for (k=0; k<=n; k++) {
            dfs(nums, path, 0);
        }
        
        return ans;
    }
};

由於這樣的搜索 O(n*2^n),所以和第一個方案比對,明顯效果差了很多。但是這個方案更加容易理解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章