修改注意点:
1、下面每次递归中变元now是代表要确定第几个位置,循环中的i代表这个位置选择哪一个元素。每次递归下去,要为i+1不是now+1.因为要从当前选择的元素开始往下选
2、有重复元素会出现相同的子集
解决办法:剪枝
策略:
先将数组进行排序,排好之后重复元素就会聚集在一起。在进行回溯的时候,循环过程中判断这个元素是否和前面一个元素相同,相同代表这个位置,此元素已经被选择过,不再选择,跳过。
注意:i=now是这个位置选择的第一个元素,不用和前面的进行判断,因为这个位置还没有选择过
代码:
package com.LeetCode1.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
/**
* 修改1:now和i
* 修改2:解决有重复元素中出现重复子集问题
*
*/
public class leet90_t {
static List<List<Integer>> ans = new LinkedList<List<Integer>>();
public static void main(String[] args) {
int[] nums = {4,4,4,1,4};
subsetsWithDup(nums);
for(int i=0;i<ans.size();i++)
{
List<Integer> l = ans.get(i);
for(int j=0;j<l.size();j++)
{
System.out.print(l.get(j)+" ");
}
System.out.println();
}
}
public static List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
for(int i=0;i<nums.length+1;i++)
{
backtrace(i,0,new ArrayList<Integer>(),nums);
}
return ans;
}
public static void backtrace(int k, int now, ArrayList<Integer> l, int[] nums) {
if(k==now)
{
if(ans.contains(l)) return;
ans.add(new ArrayList<Integer>(l));//注意此处,此处不是直接加入l,l是空的,需要按l新建一个List
return ;
}
for(int i=now;i<nums.length;i++)
{
if(i!=now&&nums[i]==nums[i-1]) continue;//关键点,大致意思:在选择的时候,如果这次以now开头的循环中,选择了与这个元素相同的元素,就不选择了
//每次循环的含义:now是选第几个元素,循环是从第几个元素开始往后选,每个位置的元素不能选择重复
l.add(nums[i]);
backtrace(k, i+1, l, nums);//此处是i+1不是now+1
l.remove(l.size()-1);
}
}
}