LeetCode Top 100 Liked Questions 78. Subsets (Java版; Medium)

welcome to my blog

LeetCode Top 100 Liked Questions 78. Subsets (Java版; Medium)

题目描述
Given a set of distinct integers, nums, return all possible subsets (the power set).

Note: The solution set must not contain duplicate subsets.

Example:

Input: nums = [1,2,3]
Output:
[
 [3],
 [1],
 [2],
 [1,2,3],
 [1,3],
 [2,3],
 [1,2],
 []
]
class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> list = new ArrayList<>();
        int n = nums.length;
        if(n==0){
            return list;
        }
        List<Integer> al = new ArrayList<>();
        backtrace(list, al, nums, 0);
        return list;
    }

    private void backtrace(List<List<Integer>> list, List<Integer> al, int[] nums, int i){
        //
        int n = nums.length;
        if(i==n){
            list.add(new ArrayList<>(al));
            return;
        }
        //not choose
        backtrace(list, al, nums, i+1);
        //choose
        al.add(nums[i]);
        backtrace(list, al, nums, i+1);
        al.remove(al.size()-1);

    }
}
第一次做, 循环追加法, 看注释; 不如回溯法和位运算直观, 其实也还行, 要明白内外循环分别做什么
/*
追加法
初始化时, 现象res中添加一个空al
外循环:遍历数组中每一个元素
内循环: 遍历res中已有的al, 每一次遍历时, 创建一个newAl, 在当前al的末尾追加当前元素, 作为newAl构造函数的参数
*/
import java.util.List;
import java.util.ArrayList;

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        if(nums==null || nums.length==0)
            return res;
        //initialize
        res.add(new ArrayList<Integer>());
        //execute
        for(int i=0; i<nums.length; i++){
            int currSize = res.size(); //记录当前res的长度, 这样就不会遍历到res中新增加的al了
            for(int j=0; j<currSize; j++){
                res.add(new ArrayList<Integer>(res.get(j))); 
                res.get(res.size()-1).add(nums[i]);
            }
        }
        return res;
    }
}
第一次做, 使用位运算, 使用范围有限, 数组长度不大于32或者64; 循环实现
/*
长度为n的数组有2^n个子数组(包括空数组)
使用位运算决定是否选择当前数, 仅适用于长度不大于32或者64的数组
*/
import java.util.List;
import java.util.ArrayList;

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        if(nums==null || nums.length==0)
            return res;
        int total = 1 << nums.length;
        //外循环表示,长度为n的数组一共有2^n个子数组(包括空数组); 从0开始的2^n个数: 0,1,...,2^n-1, 
        //这些数的二进制形式显示了所有子数组的可能, 1表示选择对应位置的元素, 0表示不选择
        for(int i=0; i<total; i++){
            res.add(new ArrayList<Integer>());
            //内循环将i表示的情况具体实现, 然后加入到res中
            for(int j=0; j<nums.length; j++){
                //i移位后, 如果最后一位是1, 把nums[nums.length - 1 - j]加入到最终结果中
                //切记: 每次只处理移位后的最后移位, 注意索引的表示, 容易错
                if(((i>>j) & 1) == 1){
                    res.get(res.size()-1).add(nums[nums.length - 1 - j]);
                }
            }
        }
        return res;
    }
}
第一次做, 回溯法:深度优先遍历+递归; 当前状态下有几种可能的操作; 改变现场, 恢复现场
/*
回溯法: 深度优先遍历+递归
回溯法中要牢记的是: 改变现场, 恢复现场
回溯法中要明确的是: 当前状态下有几种操作的可能
*/
import java.util.List;
import java.util.ArrayList;

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        if(nums==null || nums.length==0)
            return res;
        //
        ArrayList<Integer> al = new ArrayList<>();
        Core(res, al, nums, 0, nums.length);
        return res;
    }
    public void Core(List<List<Integer>> res, ArrayList<Integer> al, int[]nums, int index, int n){
        //base case
        if(index == n){
            res.add(new ArrayList<Integer>(al));
            return;
        }

        /*
        一共可以执行两种操作: 选择nums[index] 不选nums[index]
        */
        //1.选择当前元素
        //改变现场
        al.add(nums[index]);
        Core(res, al, nums, index+1, n);
        //恢复现场
        al.remove(al.size()-1);
        
        //2.不选择当前元素
        Core(res, al, nums, index+1, n);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值