90. Subsets II

本文介绍了一种解决含有重复元素的数组生成所有可能子集(幂集)的算法。通过排序和记录上次追加元素的位置,避免了重复子集的产生。以[1,2,2,3]为例,详细解释了算法的实现过程。

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],
  []
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subsets-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

方法一:

遍历每个数字,都尝试加入,用list.contains判断是否重复,代码代码简单,不赘述。

方法二:

为了避免有重复的元素,如果碰到的元素和上一个不一样,我们只在上一个元素的处理结果之后,追加元素,以{1,2,2,3}为例如下:

先对数组进行排序。

① []

②nums第一个数字1,则集合为{[],[1]}

③nums第二个数字2,与上个数字不一样,就往集合中所有的元素都追加2,放入最终集合中,则集合为{[],[1],[2],[1,2]},保存这次开始放入的元素位置为元素[2]的位置。

④nums第三个数字2,和上个数字一样,那么,就从上个元素开始放入的元素开始,之后追加。即只往集合中元素[2]和[1,2]后追加,那么集合最终为{[],[1],[2],[1,2],[2,2],[1,2,2]},保存这次开始放入的元素位置为元素[2,2]的位置。

⑤nums第四个数字3,和上数字不一样,那么久就头开始添加,最终结果是{[],[1],[2],[1,2],[2,2],[1,2,2],[3],[1,3],[2,3],[1,2,3],[2,2,3],[1,2,2,3]}

这样,我们只需要用一个数字记录,上次追加的位置即可。代码如下:

class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);
        ans.add(new ArrayList<Integer>());
        if (nums.length == 0)
            return ans;
        int lastNum = nums[0] - 1;
        int lastPutIndex = 0;
        for (int index = 0; index < nums.length; index++) {
            // 如果这个数字与上个相同,则从上次记录增加的位置开始
            if (nums[index] == lastNum) {
                int tmpSize = ans.size();
                for (int i = lastPutIndex; i < tmpSize; i++) {
                    List<Integer> list = new ArrayList<>(ans.get(i));
                    list.add(nums[index]);
                    ans.add(list);
                }
                lastPutIndex = tmpSize;
            } else {
                //不相同,则从整个集合遍历,当前集合的每个元素都加入这个数字
                int tmpSize = ans.size();
                for (int i = 0; i < tmpSize; i++) {
                    List<Integer> list = new ArrayList<>(ans.get(i));
                    list.add(nums[index]);
                    ans.add(list);
                }
                lastNum = nums[index];
                lastPutIndex = tmpSize;
            }
        }
        return ans;
    }
}

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值