算法:回溯十三 Subsets II不重复的数组子集(3种解法)

1. 题目

地址: https://leetcode.com/problems/subsets-ii/
Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).

Note: The solution set must not contain duplicate subsets.

Example:

Input: [1,2,2]
Output:
[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]

2. DFS回溯解法

思路解析:

  1. 给数组排序
  2. 当列表的长度小于等于数组长度的时候,添加到结果列表
  3. 如果当前元素与上个元素相同,则忽略。
package backtracking;

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

// https://leetcode.com/problems/subsets-ii/
public class SubsetsII {

  public static void main(String[] args) {
    int[] nums = {1,2,2};
    SubsetsII obj = new SubsetsII();
    List<List<Integer>> resultList = obj.subsetsWithDup(nums);
    System.out.println(Arrays.toString(resultList.toArray()));
  }

  public List<List<Integer>> subsetsWithDup(int[] nums) {
    Arrays.sort(nums);
    List<List<Integer>> resultList = new ArrayList<List<Integer>>();
    // dfs
    dfs(nums, resultList, new ArrayList<Integer>(), 0);

    return resultList;
  }

  private void dfs(int[] nums, List<List<Integer>> resultList, List<Integer> list, int start) {
    if (start <= nums.length) {
      resultList.add(list);
    }
    int i = start;
    while (i < nums.length) {
      list.add(nums[i]);
      dfs(nums, resultList, new ArrayList<Integer>(list), i + 1);

      list.remove(list.size() - 1);
      i++;
      while (i < nums.length && nums[i] == nums[i - 1]) {
        i++;
      }
    }

  }
}


3. 回溯解法用for循环

解题思路跟上面的一样,去重判断语句if (i > start && nums[i] == nums[i - 1]) continue; 在回溯算法里面比较通用,所以还是用这种方式同样可以解决。

public List<List<Integer>> subsetsWithDup(int[] nums) {
    Arrays.sort(nums);
    List<List<Integer>> resultList = new ArrayList<List<Integer>>();
    // dfs
    dfsWithFor(nums, resultList, new ArrayList<Integer>(), 0);
    //subsetsWithDupHelper(nums, resultList, new ArrayList<Integer>(), 0);

    return resultList;
  }

  private void dfsWithFor(int[] nums, List<List<Integer>> resultList, List<Integer> list, int start) {
    // exit
    if (start <= nums.length) {
      resultList.add(new ArrayList<>(list));
    }

    for (int i = start; i < nums.length; i++) {
      // duplicate case
      if (i > start && nums[i] == nums[i - 1]) {
        continue;
      }

      // pick up
      list.add(nums[i]);
      dfsWithFor(nums, resultList, list, i + 1);

      // not pick up
      list.remove(list.size() - 1);
    }
  }

4. 顺序执行

解题思路:

  1. 对数组nums进行升序排序
  2. 挨个遍历数组nums的元素
  3. 如果当前元素与上个元素不相同,则从位置0开始对已有结果列表resultList进行遍历,把当前元素nums[i]都加入到子列表中。
  4. 如果当前元素与上个元素相同,则从上回的结果列表的大小开始,这样子可以过滤掉相同的元素。
public List<List<Integer>> subsetsWithDupIterate(int[] nums) {
  Arrays.sort(nums);
  List<List<Integer>> resultList = new ArrayList<List<Integer>>();
  List<Integer> list = new ArrayList<Integer>();
  resultList.add(list);

  int duplicateStart = 0;
  for (int i = 0; i < nums.length; i++) {
    int begin = 0;
    int size = resultList.size();
    if (i > 0 && nums[i] == nums[i - 1]) {
      begin = duplicateStart;
    }

    for (int k = begin; k < size; k++) {
      List<Integer> newList = new ArrayList<Integer>(resultList.get(k));
      newList.add(nums[i]);
      resultList.add(newList);
    }

    duplicateStart = size;
  }

  return resultList;
}

下载

https://github.com/zgpeace/awesome-java-leetcode/blob/master/code/LeetCode/src/backtracking/SubsetsII.java

发布了127 篇原创文章 · 获赞 12 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/zgpeace/article/details/103922570