Subsets II

描述

Given a collection of integers that might contain duplicates, S, return all possible subsets.

Note:

Elements in a subset must be in non-descending order.The solution set must not contain duplicate subsets.For example,If S = [1,2,2], a solution is:

  1. [
  2. [2],
  3. [1],
  4. [1,2,2],
  5. [2,2],
  6. [1,2],
  7. []
  8. ]

分析

这题有重复元素,但本质上,跟上一题很类似,上一题中元素没有重复,相当于每个元素只能选0或1次,这里扩充到了每个元素可以选0到若干次而已。

递归

增量构造法

  1. // Subsets II
  2. // 增量构造法,版本1,时间复杂度O(2^n),空间复杂度O(n)
  3. public class Solution {
  4. public List<List<Integer>> subsetsWithDup(int[] nums) {
  5. Arrays.sort(nums); // 必须排序
  6. List<List<Integer>> result = new ArrayList<>();
  7. List<Integer> path = new ArrayList<>();
  8. dfs(nums, 0, path, result);
  9. return result;
  10. }
  11. private static void dfs(int[] nums, int start, List<Integer> path,
  12. List<List<Integer>> result) {
  13. result.add(new ArrayList<Integer>(path));
  14. for (int i = start; i < nums.length; i++) {
  15. if (i != start && nums[i] == nums[i-1]) continue;
  16. path.add(nums[i]);
  17. dfs(nums, i + 1, path, result);
  18. path.remove(path.size() - 1);
  19. }
  20. }
  21. }
  1. // Subsets II
  2. // 增量构造法,版本2,时间复杂度O(2^n),空间复杂度O(n)
  3. public class Solution {
  4. public List<List<Integer>> subsetsWithDup(int[] nums) {
  5. Arrays.sort(nums); // 必须排序
  6. List<List<Integer>> result = new ArrayList<>();
  7. List<Integer> path = new ArrayList<>(); // 中间结果
  8. // 记录每个元素的出现次数
  9. HashMap<Integer, Integer> counterMap = new HashMap<>();
  10. for (int i : nums) {
  11. counterMap.put(i, counterMap.getOrDefault(i, 0) + 1);
  12. }
  13. // 将HashMap里的pair拷贝到一个数组里
  14. Pair[] counters = new Pair[counterMap.size()];
  15. int i = 0;
  16. for (Map.Entry<Integer, Integer> entry : counterMap.entrySet()) {
  17. counters[i++] = new Pair(entry.getKey(), entry.getValue());
  18. }
  19. Arrays.sort(counters);
  20. dfs(counters, 0, path, result);
  21. return result;
  22. }
  23. private static void dfs(Pair[] counters, int step, List<Integer> path,
  24. List<List<Integer>> result) {
  25. if (step == counters.length) {
  26. result.add(new ArrayList<>(path));
  27. return;
  28. }
  29. for (int i = 0; i <= counters[step].value; i++) {
  30. for (int j = 0; j < i; ++j) {
  31. path.add(counters[step].key);
  32. }
  33. dfs(counters, step + 1, path, result);
  34. for (int j = 0; j < i; ++j) {
  35. path.remove(path.size() - 1);
  36. }
  37. }
  38. }
  39. static class Pair implements Comparable<Pair> {
  40. int key;
  41. int value;
  42. public Pair(int key, int value) {
  43. this.key = key;
  44. this.value = value;
  45. }
  46. @Override
  47. public int compareTo(Pair o) {
  48. if (this.key < o.key) return -1;
  49. else if (this.key > o.key) return 1;
  50. else {
  51. return this.value - o.value;
  52. }
  53. }
  54. }
  55. }

位向量法

  1. // Subsets II
  2. // 位向量法,时间复杂度O(2^n),空间复杂度O(n)
  3. public class Solution {
  4. public List<List<Integer>> subsetsWithDup(int[] nums) {
  5. Arrays.sort(nums); // 必须排序
  6. List<List<Integer>> result = new ArrayList<>();
  7. // 记录每个元素的出现次数
  8. HashMap<Integer, Integer> counterMap = new HashMap<>();
  9. for (int i : nums) {
  10. counterMap.put(i, counterMap.getOrDefault(i, 0) + 1);
  11. }
  12. // 将HashMap里的pair拷贝到一个数组里
  13. Pair[] counters = new Pair[counterMap.size()];
  14. int i = 0;
  15. for (Map.Entry<Integer, Integer> entry : counterMap.entrySet()) {
  16. counters[i++] = new Pair(entry.getKey(), entry.getValue());
  17. }
  18. Arrays.sort(counters);
  19. // 每个元素选择了多少个
  20. HashMap<Integer, Integer> selected = new HashMap<>();
  21. for (Pair p : counters) {
  22. selected.put(p.key, 0 );
  23. }
  24. dfs(nums, counters, selected, 0, result);
  25. return result;
  26. }
  27. private static void dfs(int[] nums, Pair[] counters, HashMap<Integer, Integer> selected,
  28. int step, List<List<Integer>> result) {
  29. if (step == counters.length) {
  30. ArrayList<Integer> subset = new ArrayList<>();
  31. for (Pair p : counters) {
  32. for (int i = 0; i < selected.get(p.key); ++i) {
  33. subset.add(p.key);
  34. }
  35. }
  36. result.add(subset);
  37. return;
  38. }
  39. for (int i = 0; i <= counters[step].value; i++) {
  40. selected.put(counters[step].key, i);
  41. dfs(nums, counters, selected, step + 1, result);
  42. }
  43. }
  44. static class Pair implements Comparable<Pair> {
  45. int key;
  46. int value;
  47. public Pair(int key, int value) {
  48. this.key = key;
  49. this.value = value;
  50. }
  51. @Override
  52. public int compareTo(Pair o) {
  53. if (this.key < o.key) return -1;
  54. else if (this.key > o.key) return 1;
  55. else {
  56. return this.value - o.value;
  57. }
  58. }
  59. }
  60. }

迭代

增量构造法

  1. // Subsets II
  2. // 增量构造法
  3. // 时间复杂度O(2^n),空间复杂度O(1)
  4. public class Solution {
  5. public List<List<Integer>> subsetsWithDup(int[] nums) {
  6. Arrays.sort(nums); // 必须排序
  7. List<List<Integer>> result = new ArrayList<>();
  8. result.add(new ArrayList<Integer>());
  9. int previous_size = 0;
  10. for (int i = 0; i < nums.length; ++i) {
  11. final int size = result.size();
  12. for (int j = 0; j < size; ++j) {
  13. if (i == 0 || nums[i] != nums[i-1] || j >= previous_size) {
  14. result.add(new ArrayList<>(result.get(j)));
  15. result.get(result.size() - 1).add(nums[i]);
  16. }
  17. }
  18. previous_size = size;
  19. }
  20. return result;
  21. }
  22. }

二进制法

  1. // Subsets II
  2. // 二进制法,时间复杂度O(2^n),空间复杂度O(1)
  3. public class Solution {
  4. public List<List<Integer>> subsetsWithDup(int[] nums) {
  5. Arrays.sort(nums); // 必须排序
  6. // 用 set 去重,不能用 unordered_set,因为输出要求有序
  7. LinkedHashSet<ArrayList<Integer>> result = new LinkedHashSet<>();
  8. final int n = nums.length;
  9. ArrayList<Integer> v = new ArrayList<>();
  10. for (int i = 0; i < 1 << n; ++i) {
  11. for (int j = 0; j < n; ++j) {
  12. if ((i & 1 << j) > 0)
  13. v.add(nums[j]);
  14. }
  15. result.add(new ArrayList<>(v));
  16. v.clear();
  17. }
  18. List<List<Integer>> realResult = new ArrayList<>();
  19. for (ArrayList<Integer> list : result) {
  20. realResult.add(list);
  21. }
  22. return realResult;
  23. }
  24. }

相关题目

原文: https://soulmachine.gitbooks.io/algorithm-essentials/content/java/brute-force/subsets-ii.html