1.求集合的所有子集(又稱全組合)
求一個集合的所有組合,例如集合{A,B,C}的所有子集為:{},{A,B,C},{A,B},{A,C},{B,C},{A},{B},{C}。
思路
對于任意集合A,元素個數為n(空集n=0),則所有子集的個數為2^n個
如集合A={a,b,c},其子集個數為8;對于任意一個元素,在每個子集中,
要麼存在,要麼不存在,對應關系是:
a=1或a=0,b=1或b=0,c=1或c=0
映射為子集:
(1,1,1)->(a,b,c)
(1,1,0)->(a,b )
(1,0,1)->(a, c)
(1,0,0)->(a )
(0,1,1)->( b,c)
(0,1,0)->( b )
(0,0,1)->( c)
(0,0,0)->( ) 空集
觀察以上規律,與計算機中資料存儲方式相似,故可以通過(a=100,b=010,c=001)與集合映射000 - 111(0表示有,1表示無)作與運算,即擷取集合的相應子集。
算法1:
位圖法:
1)構造一個和集合一樣大小的數組A,分别與集合中的某個元素對應,數組A中的元素隻有兩種狀态:“1”和“0”,分别代表每次子集輸出中集合中對應元素是否要輸出,這樣數組A可以看作是原集合的一個标記位圖。
2)數組A模拟整數“加一”的操作,每“加一”之後,就将原集合中所有與數組A中值為“1”的相對應的元素輸出。
代碼如下
/**
* 擷取所有子集
*/
private static ArrayList<ArrayList<Integer>> getSubList(int[] arr) {
ArrayList<ArrayList<Integer>> allList = new ArrayList<>();
int size = 1 << arr.length;// 2^n次方
for (int mark = 0; mark < size; mark++) {
ArrayList<Integer> aList = new ArrayList<>();
for (int i = 0; i < arr.length; i++) {
/* 重要:這句是最重要的代碼:是 0-7 分别與運算 1,2,4
* 000 001 010 011 100 101 110 111
*
*/
if ((mark & (1 << i)) != 0) {
aList.add(arr[i]);
}
}
allList.add(aList);
}
return allList;
}
public static void main(String[] args) {
int[] arr= {1,2,3};
ArrayList<ArrayList<Integer>> list = getSubList(arr);
for (int i=0;i<list.size();i++) {
ArrayList<Integer> mList=list.get(i);
for (int j=0;j<mList.size();j++) {
System.out.print(mList.get(j)+" ");
}
//換行
System.out.println();
}
}
算法2:遞歸疊代法:
public class Demo {
public static void main(String[] args) {
int[] arr = {1, 2};
Set<Set<Integer>> f = f(arr.length, arr);
System.out.println(f);
}
public static Set<Set<Integer>> f(int k, int[] arr) {
if (k == 0) {
Set<Set<Integer>> set = new HashSet<>();
set.add(new HashSet<>());//添加一個空集合
return set;
}
Set<Set<Integer>> set = f(k - 1, arr);
Set<Set<Integer>> resultSet = new HashSet<>();
for (Set<Integer> integerSet : set) {//掃描上一層的集合
//上一層的每個集合都包含兩種情況,一種是加入新來的元素,另一種是不加入新的元素
HashSet<Integer> subSet = new HashSet<>();
subSet.addAll(integerSet);
subSet.add(arr[k - 1]);
resultSet.add(subSet);
resultSet.add(integerSet);
}
return resultSet;
}
}
2.求集合的所有排列(又稱全排列)
一,問題描述
給定一個字元串,求出該字元串的全排列。
比如:"abc"的全排列是:abc、acb、bac、bca、cab、cba
二,實作思路
* 從集合中依次選出每一個元素,作為排列的第一個元素,然後對剩餘的元素進行全排列,如此遞歸處理,
* 進而得到所有元素的全排列。以對字元串abc進行全排列為例,我們可以這麼做:以abc為例:
* 固定a,求後面bc的排列:abc,acb,求好後,a和b交換,得到bac
* 固定b,求後面ac的排列:bac,bca,求好後,c放到第一位置,得到cba
* 固定c,求後面ba的排列:cba,cab。
*
* 即遞歸樹:
str: a b c
ab ac ba bc ca cb
result: abc acb bac bca cab cba
/*
* 全排列
*/
public static void permutation(String str, String result) {
/* 全排列 遞歸實作
遞歸樹:
str: a b c
ab ac ba bc ca cb
result: abc acb bac bca cab cba
*/
// 當result長度等于長度,說明已經周遊到葉子節點,直接列印
if (result.length() == str.length()) { // 表示周遊完了一個全排列結果
System.out.println(result);
} else {
for (int i = 0; i < str.length(); i++) {
// 判斷result中沒有 a、b、c
if (result.indexOf(str.charAt(i)) < 0) {
permutation(str, result + str.charAt(i));
}
}
}
}
public static void main(String args[]) throws Exception {
String str="abc";
permutation(str,"");
}
3.求集合的所有子序列(即所有的排列組合)
思路:
子序列和子集合不一樣,子序列有順序差别,子集合沒有順序,子序列為所有子集合的排列組合,即集合的所有子序列 = 集合的所有子集合的排列組合集。
/*
* 擷取所有子集(全組合)
*/
private static List<String> combination(String str) {
ArrayList<String> allList = new ArrayList<>();
int size = 1 << str.length();// 2^n次方
for (int mark = 0; mark < size; mark++) {
ArrayList<String> aList = new ArrayList<>();
for (int i = 0; i < str.length(); i++) {
/* 重要:這句是最重要的代碼:是 0-7 分别與運算 1,2,4
* 000 001 010 011 100 101 110 111
*
*/
if ((mark & (1 << i)) != 0) {
aList.add(str.charAt(i)+"");
}
}
allList.add(String.join("", aList));
}
//allList.forEach((item)->{System.out.println(item);});
return allList;
}
/*
* 全排列
*/
public static void permutation(String str, String result, List<String> allResult) {
/* 全排列 遞歸實作
遞歸樹:
str: a b c
ab ac ba bc ca cb
result: abc acb bac bca cab cba
*/
// 結果 開始傳入"" 空字元進入 len 是這個數的長度
if (result.length() == str.length()) {
// 表示周遊完了一個全排列結果
allResult.add(result);
} else {
for (int i = 0; i < str.length(); i++) {
// 傳回指定字元在此字元串中第一次出現處的索引。
if (result.indexOf(str.charAt(i)) < 0) {
permutation(str, result + str.charAt(i), allResult);
}
}
}
}
public static void main(String[] args) {
String str="abc";
List<String> allList = combination(str);
List<String> allSequence = new ArrayList<>();
allList.forEach((item)->{
List<String> sequence = new ArrayList<>();
permutation(item,"",sequence);
allSequence.addAll(sequence);
});
allSequence.forEach((item)->{System.out.println(item);});
}
列印結果