package com.freetymekiyan.algorithms.level.medium; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.util.ArrayList; import java.util.List; /** * Given a set of distinct integers, nums, return all possible subsets. * <p> * Note: The solution set must not contain duplicate subsets. * <p> * For example, * If nums = [1,2,3], a solution is: * <p> * | [ * | [3], * | [1], * | [2], * | [1,2,3], * | [1,3], * | [2,3], * | [1,2], * | [] * | ] * Company Tags: Amazon, Uber, Facebook * Tags: Array, Backtracking, Bit Manipulation * Similar Problems: (M) Generalized Abbreviation */ public class Subsets { private Subsets s; /** * Backtracking. * Visit: * Backtrack without current number. * Then add the number and backtrack again. * Reset. * Base case: * When the end of array is reached, add de-referenced subset to result and return. */ public List<List<Integer>> subsetsA(int[] nums) { List<List<Integer>> res = new ArrayList<>(); backtrackA(res, nums, 0, new ArrayList<>()); return res; } private void backtrackA(List<List<Integer>> res, int[] nums, int pos, List<Integer> subset) { if (pos == nums.length) { res.add(new ArrayList<>(subset)); return; } backtrackA(res, nums, pos + 1, subset); // Without current number. subset.add(nums[pos]); backtrackA(res, nums, pos + 1, subset); // With current number. subset.remove(subset.size() - 1); // Reset. } /** * Backtracking. */ public List<List<Integer>> subsetsB(int[] nums) { List<List<Integer>> res = new ArrayList<>(); subsetsB(res, nums, 0, new ArrayList<>()); return res; } /** * DFS. * Add current subset to result first. * Put current number in subset. * Then backtrack with the rest of the numbers. * Reset by remove last number in subset. * Next iteration will move to next number then all subsets will not have this number. */ public void subsetsB(List<List<Integer>> sets, int[] nums, int pos, List<Integer> subset) { sets.add(new ArrayList<>(subset)); // Dereference and add current subset to result. for (int i = pos; i < nums.length; i++) { subset.add(nums[i]); // With nums[i]. subsetsB(sets, nums, i + 1, subset); // Backtrack to generate add subsets with s[i]. subset.remove(subset.size() - 1); // Remove s[i], next round there won't be s[i]. } } /** * Iterative. * Build from empty set to the next subsets. * Adding each subset the current num, new subsets are generated. * Then add new subsets to all subsets and generate next round. * Stop when we iterate through the array. * E.g.: * [] -> [] [1] * [] [1] -> [] [1] [2] [1, 2] */ public List<List<Integer>> subsetsC(int[] nums) { List<List<Integer>> subsets = new ArrayList<>(); subsets.add(new ArrayList<>()); // Add empty set. for (int i = 0; i < nums.length; i++) { int n = subsets.size(); for (int j = 0; j < n; j++) { List<Integer> set = new ArrayList<>(subsets.get(j)); // Dereference. set.add(nums[i]); subsets.add(set); } } return subsets; } @Before public void setUp() { s = new Subsets(); } @Test public void testExamples() { int[] nums = {1, 2, 3}; List<List<Integer>> res = s.subsetsB(nums); System.out.println(res.toString()); } @After public void tearDown() { s = null; } }