集合的所有子集(二)
https://www.nowcoder.com/practice/a3dfd4bc8ae74fad9bc65d5ced7ae813
import java.util.*;
/**
* NC221 集合的所有子集(二)
* @author d3y1
*/
public class Solution {
private ArrayList<Integer> list = new ArrayList<>();
private ArrayList<ArrayList<Integer>> result = new ArrayList<>();
private HashSet<ArrayList<Integer>> set = new HashSet<>();
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 相似 -> NC27 集合的所有子集(一) [nowcoder]
*
* @param nums int整型一维数组
* @return int整型ArrayList<ArrayList<>>
*/
public ArrayList<ArrayList<Integer>> subsets (int[] nums) {
return solution1(nums);
// return solution2(nums);
// return solution22(nums);
// return solution222(nums);
// return solution3(nums);
// return solution33(nums);
}
/**
* 位运算
*
* 考虑数组[1,2,2], 选择前两个数, 或者第一、三个数, 都会得到相同的子集.
*
* 也就是说, 对于当前选择的数x, 若前面有与其相同的数y, 且没有选择y, 此时包含x的子集, 必然会出现在包含y的所有子集中.
*
* 我们可以通过判断这种情况, 来避免生成重复的子集.
* 代码实现时, 可以先将数组排序; 迭代时, 若发现没有选择上一个数, 且当前数与上一个数相同, 则可以跳过当前生成的子集.
*
* @param S
* @return
*/
private ArrayList<ArrayList<Integer>> solution1(int[] S){
int n = S.length;
if(n == 0){
return new ArrayList<>();
}
Arrays.sort(S);
boolean flag;
for(int mask=0; mask<(1<<n); mask++){
list.clear();
flag = true;
for(int j=0; j<n; j++){
if(((mask>>j)&1) == 1){
// 没有选择上一个数, 且当前数与上一个数相同
if(j>0 && (((mask>>(j-1))&1)==0) && S[j]==S[j-1]){
flag = false;
break;
}
list.add(S[j]);
}
}
if(flag){
result.add(new ArrayList<>(list));
}
}
sort(result);
return result;
}
/**
* 回溯法
* @param S
* @return
*/
private ArrayList<ArrayList<Integer>> solution2(int[] S){
int n = S.length;
if(n == 0){
return new ArrayList<>();
}
Arrays.sort(S);
backtrack2(S, 0, new ArrayList<>());
return result;
}
/**
* 回溯: 递归遍历解空间
* @param S
* @param idx
* @param list
*/
private void backtrack2(int[] S, int idx, ArrayList<Integer> list){
if(!set.contains(list)){
result.add(list);
set.add(list);
}
ArrayList<Integer> newList;
for(int i=idx; i<S.length; i++){
newList = new ArrayList<>(list);
newList.add(S[i]);
backtrack2(S, i+1, newList);
}
}
/**
* 回溯法
* @param S
* @return
*/
private ArrayList<ArrayList<Integer>> solution22(int[] S){
int n = S.length;
if(n == 0){
return new ArrayList<>();
}
Arrays.sort(S);
backtrack22(S, 0, new ArrayList<>());
return result;
}
/**
* 回溯: 递归遍历解空间
* @param S
* @param idx
* @param list
*/
private void backtrack22(int[] S, int idx, ArrayList<Integer> list){
if(!set.contains(list)){
result.add(new ArrayList<>(list));
set.add(new ArrayList<>(list));
}
for(int i=idx; i<S.length; i++){
list.add(S[i]);
backtrack22(S, i+1, list);
list.remove(list.size()-1);
}
}
/**
* 回溯法
* @param S
* @return
*/
private ArrayList<ArrayList<Integer>> solution222(int[] S){
int n = S.length;
if(n == 0){
return new ArrayList<>();
}
Arrays.sort(S);
backtrack222(S, 0);
return result;
}
/**
* 回溯: 递归遍历解空间
* @param S
* @param idx
*/
private void backtrack222(int[] S, int idx){
result.add(new ArrayList<>(list));
for(int i=idx; i<S.length; i++){
// 没有选择上一个数, 且当前数与上一个数相同
if(i>idx && S[i]==S[i-1]){
continue;
}
list.add(S[i]);
backtrack222(S, i+1);
list.remove(list.size()-1);
}
}
/**
* 回溯法
* @param S
* @return
*/
private ArrayList<ArrayList<Integer>> solution3(int[] S){
int n = S.length;
if(n == 0){
return new ArrayList<>();
}
Arrays.sort(S);
backtrack3(S, 0);
sort(result);
return result;
}
/**
* 回溯: 递归遍历解空间
* @param S
* @param idx
*/
private void backtrack3(int[] S, int idx){
if(idx == S.length){
result.add(new ArrayList<Integer>(list));
return;
}
list.add(S[idx]);
backtrack3(S, idx+1);
list.remove(list.size()-1);
// 没有选择当前数(上面remove()), 且下一个数与当前数相同
while(idx<S.length-1 && S[idx]==S[idx+1]){
idx++;
}
backtrack3(S, idx+1);
}
/**
* 回溯法
* @param S
* @return
*/
private ArrayList<ArrayList<Integer>> solution33(int[] S){
int n = S.length;
if(n == 0){
return new ArrayList<>();
}
Arrays.sort(S);
backtrack33(S, 0, false);
sort(result);
return result;
}
/**
* 回溯: 递归遍历解空间
* @param S
* @param idx
* @param choosePre
*/
private void backtrack33(int[] S, int idx, boolean choosePre){
if(idx == S.length){
result.add(new ArrayList<Integer>(list));
return;
}
backtrack33(S, idx+1, false);
// 没有选择上一个数, 且当前数与上一个数相同
if(!choosePre && idx>0 && S[idx]==S[idx-1]){
return;
}
list.add(S[idx]);
backtrack33(S, idx+1, true);
list.remove(list.size()-1);
}
/**
* 排序结果集: 按字典序
* @param result
*/
private void sort(ArrayList<ArrayList<Integer>> result){
// Collections.sort(result, new Comparator<ArrayList<Integer>>(){
// @Override
// public int compare(ArrayList<Integer> o1, ArrayList<Integer> o2){
// int len = Math.min(o1.size(), o2.size());
// for(int i=0; i<len; i++){
// if(o1.get(i) != o2.get(i)){
// return o1.get(i)-o2.get(i);
// }
// }
// return o1.size()-o2.size();
// }
// });
Collections.sort(result, (o1, o2) -> {
int len = Math.min(o1.size(), o2.size());
for(int i=0; i<len; i++){
if(!o1.get(i).equals(o2.get(i))){
return o1.get(i)-o2.get(i);
}
}
return o1.size()-o2.size();
});
}
}