面试算法79:所有子集

题目

输入一个不含重复数字的数据集合,请找出它的所有子集。例如,数据集合[1,2]有4个子集,分别是[]、[1]、[2]和[1,2]。

分析

如果集合中包含n个元素,那么生成子集可以分为n步,每一步从集合中取出一个数字,此时面临两个选择,将该数字添加到子集中或不将该数字添加到子集中。生成一个子集可以分为若干步,并且每一步都面临若干选择,这正是应用回溯法的典型场景。
适用回溯法的问题的一个特征是问题可能有很多个解,并且题目要求列出所有的解。如果题目只是要求计算解的数目,或者只需要求一个最优解(通常是最大值或最小值),那么可能需要运用动态规划。

public class Test {
    public static void main(String[] args) {
        int[] nums = {1, 2};
        List<List<Integer>> result = subsets(nums);
        for (List<Integer> item : result) {
            System.out.println(item);
        }
    }

    public static List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> result = new LinkedList<>();
        if (nums.length == 0) {
            return result;
        }

        helper(nums, 0, new LinkedList<Integer>(), result);
        return result;
    }

    private static void helper(int[] nums, int index, LinkedList<Integer> subset, List<List<Integer>> result) {
        if (index == nums.length) {
            result.add(new LinkedList<>(subset));
        }
        else if (index < nums.length) {
            helper(nums, index + 1, subset, result);// 直接不添加元素

            subset.add(nums[index]);// 添加元素
            helper(nums, index + 1, subset, result);
            // 等递归函数执行完成之后,函数helper也执行完成,接下来将回到前一个数字的函数调用处继续执行。那么此时将回溯到父节点,以便尝试父节点的其他选项。
            // 在回溯到父节点之前,应该清除已经对子集状态进行的修改。此前在子集subset中添加了一个数字,此时应该将它删除。
            subset.removeLast();
        }
    }
}

你可能感兴趣的:(算法,面试,算法,java)