【LeetCode 78】子集

第一種:回溯解法

    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> answer=new ArrayList<>();
        if (nums == null || nums.length == 0) {
            return answer;
        }

        subsetsCore(nums,0,answer,new ArrayList<>());
        return answer;
    }

    public void subsetsCore(int[] nums, int index, List<List<Integer>> answer, List<Integer> currentAns) {
        answer.add(new ArrayList<>(currentAns));
        for(int i=index;i<nums.length;i++){
            currentAns.add(nums[i]);
            subsetsCore(nums,i+1,answer,currentAns);
            currentAns.remove(currentAns.size()-1);
        }
    }

第二種:暴力解法

從[]解集開始,掃描一遍元素,每掃描到一個元素就添加到當前所有解裏面,同時原有解保持不變。

class Solution {
  public List<List<Integer>> subsets(int[] nums) {
    List<List<Integer>> output = new ArrayList();
    output.add(new ArrayList<Integer>());

    for (int num : nums) {
      List<List<Integer>> newSubsets = new ArrayList();
      for (List<Integer> curr : output) {
        newSubsets.add(new ArrayList<Integer>(curr){{add(num);}});
      }
      for (List<Integer> curr : newSubsets) {
        output.add(curr);
      }
    }
    return output;
  }
}

作者:LeetCode
鏈接:https://leetcode-cn.com/problems/subsets/solution/zi-ji-by-leetcode/
來源:力扣(LeetCode)

第三種:遞歸解法

對元素的選擇可以構成一顆二叉樹,樹根爲第一個元素,左子樹代表解集包含當前結點,右子樹代表解集不包含當前結點,第二層是第二個元素...etc。從樹的根結點向下遞歸搜索,即可獲得所有子集。

    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> answer=new ArrayList<>();
        if (nums == null || nums.length == 0) {
            return answer;
        }

        subsetsCore(nums,0,answer,new ArrayList<>());
        return answer;
    }

    public void subsetsCore(int[] nums, int index, List<List<Integer>> answer, List<Integer> currentAns) {
        if(index>=nums.length){
            //最終將結果構建葉子結點存儲到解集
            answer.add(new ArrayList<>(currentAns));
            return;
        }
        //這一步是爲了構建中間結點,避免多個遞歸過程中修改同一個對象
        List<Integer> currentAnsTmp=new ArrayList<>(currentAns);
        subsetsCore(nums,index+1,answer,currentAnsTmp);
        currentAnsTmp.add(nums[index]);
        subsetsCore(nums,index+1,answer,currentAnsTmp);
    }

第四種:二進制映射方法求解

因爲含有n個元素的集合的子集,正好相當於n個bit隨機填充0或1的所有情況,也就是[0,2^n-1)的所有數值,每一個數值表示一個子集,數值bit爲1表示元素在子集中。

class Solution {
  public List<List<Integer>> subsets(int[] nums) {
    List<List<Integer>> output = new ArrayList();
    int n = nums.length;

    for (int i = (int)Math.pow(2, n); i < (int)Math.pow(2, n + 1); ++i) {
      // generate bitmask, from 0..00 to 1..11
      String bitmask = Integer.toBinaryString(i).substring(1);

      // append subset corresponding to that bitmask
      List<Integer> curr = new ArrayList();
      for (int j = 0; j < n; ++j) {
        if (bitmask.charAt(j) == '1') curr.add(nums[j]);
      }
      output.add(curr);
    }
    return output;
  }
}
來源:LeetCode

 

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