[LeetCode&Algorithms]78.Subsets/子集/回溯法Backtracking+dfs詳解

參考了以下的人終於搞懂了點

參考1

參考2

參考3

78 子集
  給定一組不含重複元素的整數數組 nums,返回該數組所有可能的子集(冪集)。
  說明:解集不能包含重複的子集。
  Given a set of distinct integers, nums, return all possible subsets (the power set).
  Note: The solution set must not contain duplicate subsets.

/*思路1
 * Backtracking+dfs
 * 回溯+深度優先搜索
 * 如果要理解,看到一個解釋,也可以當作:存在和不存在。
 * 外層循環逐一往中間集合 temp 中加入元素 nums[i],使這個元素處於存在狀態
 * 開始遞歸,遞歸中攜帶加入新元素的 temp,並且下一次循環的起始是 i 元素的下一個,因而遞歸中更新 i 值爲 i + 1
 * 將這個從中間集合 temp 中移除,使該元素處於不存在狀態
 * */
  public static List<List<Integer>> subsets(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> temp = new ArrayList<>();
        dfs(res, temp, nums, 0);
        return res;
    }

 

/* * 再具體點
 * 形如[1,2,3]得到
 * [[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]
 * 假設某一步 temp=》 tempList.add(nums[i])=>[1]
 * 在進行dfs的時候是[1]add下一層=》[1,2]=>再下一層dfs->[1,2,3],結束後往上回溯remove 3 =>[1,2]
 * 繼續回溯會變爲remove 2 =>[1] 最外層remove 1 =》[]
 * 最最外層循環結束,i++,從num[1]=2開始=temp=>[2]
 * */
 private static void dfs(List<List<Integer>> list, List<Integer> tempList, int[] nums, int start) {
        list.add(new ArrayList<>(tempList));
        for (int i = start; i < nums.length; i++) {
            tempList.add(nums[i]);
            dfs(list, tempList, nums, i + 1);
            tempList.remove(tempList.size() - 1);
        }
    }

附帶循環的思路

package Array.Medium;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/*78 子集
 * 給定一組不含重複元素的整數數組 nums,返回該數組所有可能的子集(冪集)。
 * 說明:解集不能包含重複的子集。
 * Given a set of distinct integers, nums, return all possible subsets (the power set).
 * Note: The solution set must not contain duplicate subsets.
 * */
public class Subsets {


    /*思路1
     * Backtracking+dfs
     * 回溯+深度優先搜索
     * 如果要理解,看到一個解釋,也可以當作:存在和不存在。
     * 外層循環逐一往中間集合 temp 中加入元素 nums[i],使這個元素處於存在狀態
     * 開始遞歸,遞歸中攜帶加入新元素的 temp,並且下一次循環的起始是 i 元素的下一個,因而遞歸中更新 i 值爲 i + 1
     * 將這個從中間集合 temp 中移除,使該元素處於不存在狀態
     * */

    public static List<List<Integer>> subsets1(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> temp = new ArrayList<>();
        dfs(res, temp, nums, 0);
        return res;
    }

    /* * 再具體點
     * 形如[1,2,3]得到
     * [[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]
     * 假設某一步 temp=》 tempList.add(nums[i])=>[1]
     * 在進行dfs的時候是[1]add下一層=》[1,2]=>再下一層dfs->[1,2,3],結束後往上回溯remove 3 =>[1,2]
     * 繼續回溯會變爲remove 2 =>[1] 最外層remove 1 =》[]
     * 最最外層循環結束,i++,從num[1]=2開始=temp=>[2]
     * */
    private static void dfs(List<List<Integer>> list, List<Integer> tempList, int[] nums, int start) {
        list.add(new ArrayList<>(tempList));
        for (int i = start; i < nums.length; i++) {
            tempList.add(nums[i]);
            dfs(list, tempList, nums, i + 1);
            tempList.remove(tempList.size() - 1);
        }
    }

    /*思路3
     * 選和不選+二進制
     * [ 1 , 2 , 3 ]
     *   f   f   f   []
     *   t   f   f   [1]
     *   t   t   f   [1,2]
     *   ...類推
     * */

    /*思路2
     * 遍歷
     * 出現新的,就把新的添加到上一層子集的後面
     * 詳解
     * res的size是遞增的
     * 外層遍歷每個nums的元素
     * 內層遍歷res的元素,被外層當前元素add進temp再add進res即可
     * */
    public static List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        res.add(new ArrayList<>());
        for (int num : nums) {  // ①從數組中取出每個元素
            int size = res.size();
            for (int i = 0; i < size; i++) {
                List<Integer> temp = new ArrayList<>(res.get(i));  // ②逐一取出中間結果集
                System.out.println(res.get(i));
                temp.add(num);  // ③將 num 放入中間結果集
                res.add(temp);  // ④加入到結果集中
            }
        }
        return res;
    }


    public static void main(String[] args) {
        int[] num = {1, 2, 3};
        System.out.println(subsets(num));

    }
}

 

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