LintCode 17. 子集subsets

subsets这题非递归的写法很好写,递归DFS我一直没想到递归的退出条件,没想到是没有,运行完了自动退出,return;再末尾,和partition得到字符串字串类似的通过控制startIndex控制循环从而得到从数组startIndex开始的子串

import org.junit.Test;

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

public class Subsets {
    /**
     * @param nums: A set of numbers
     * @return: A list of lists
     *
     * 17. 子集
     * 给定一个含不同整数的集合,返回其所有的子集
     *
     * 样例
     * 如果 S = [1,2,3],有如下的解:
     *
     * [
     *   [3],
     *   [1],
     *   [2],
     *   [1,2,3],
     *   [1,3],
     *   [2,3],
     *   [1,2],
     *   []
     * ]
     * 挑战
     * 你可以同时用递归与非递归的方式解决么?
     *
     * 注意事项
     * 子集中的元素排列必须是非降序的,解集必须不包含重复的子集
     */

    /**
     * 求子集问题是经典的NP问题,复杂度上我们就无法强求了哈,肯定是非多项式量级的。
     * 一般来说这个问题有两种解法:递归和非递归。
     * 我们先来说说递归解法,主要递推关系就是假设函数返回递归集合,现在加入一个新的数字,
     * 我们如何得到包含新数字的所有子集。其实就是在原有的集合中对每集合中的每个元素都加
     * 入新元素得到子集,然后放入原有集合中(原来的集合中的元素不用删除,因为他们也是合
     * 法子集)。而结束条件就是如果没有元素就返回空集(注意空集不是null,而是没有元素的
     * 数组)就可以了。时间和空间都是取决于结果的数量,也就是O(2^n)
     *
     * @param nums
     * @return
     */
    public List<List<Integer>> subsets(int[] nums) {
        // write your code here
        List<List<Integer>> result = new ArrayList<>();
        List<Integer> list = new ArrayList<>();
        if (nums == null) {
            return result;
        }
        if (nums.length == 0) {
            result.add(list);
            return result;
        }
        Arrays.sort(nums);
        int startIndex = 0;
        helper2(list,nums,startIndex,result);
//        helper1(result, list, nums);
        return result;
    }

    //非递归
    private void helper1(List<List<Integer>> result, List<Integer> list, int[] nums) {
        if (result.size() == 0) {
            result.add(new ArrayList<>(list));
        }
        for (int i = 0; i < nums.length; i++) {
            int num = result.size();
            for (int j = 0; j < num; j++) {
                List<Integer> list2 = new ArrayList<>(result.get(j));
                list2.add(nums[i]);
                result.add(list2);
            }
        }
    }

    //递归 DFS
    // 递归三要素
    // 1. 递归的定义:在 Nums 中找到所有以 subset 开头的的集合,并放到 results
    private void helper2(List<Integer> subset,
                        int[] nums,
                        int startIndex,
                        List<List<Integer>> results) {
        // 2. 递归的拆解
        // deep copy
        // results.add(subset);
        results.add(new ArrayList<Integer>(subset));

        for (int i = startIndex; i < nums.length; i++) {
            // [1] -> [1,2]
            subset.add(nums[i]);
            System.out.println("+:"+subset.toString());

            // 寻找所有以 [1,2] 开头的集合,并扔到 results
            helper2(subset, nums, i + 1, results);
            // [1,2] -> [1]  回溯
            subset.remove(subset.size() - 1);
            System.out.println("-:"+subset.toString());

        }

        // 3. 递归的出口
        // return;
    }

    @Test
    public void testSubsets() {
        List<List<Integer>> result = subsets(new int[]{1, 2, 3, 4});
//        for (int i = 0; i < result.size(); i++) {
//            System.out.println(result.get(i).toString());
//        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_37859539/article/details/81674472