給定隨意長度的一個集合。用一個數組表示,如{"a", "b","c"},求它的所有子集。結果是{ {a}, {b}, {c}, {a,b}, {a,c}, {b,c}, {a,b,c}}和一個空集。java
如下講的就是怎樣用一個原始的傻瓜方法(非算法)求它的所有子集。算法
首先咱們知道是它的子集個數是2^length,假設長度是3,那子集就共同擁有2的3次方=8個,包含空集。數組
求子集,個人作法是對不論什麼一項作推斷,有或者無,用1和0來相應表示。post
那麼像這樣的長度爲3的,用二進制來表示就是000、00一、010……ui
事實上就是從0-2^3,用2進製表示出來就是因此的子集了。而後把0相應的子項給拿掉。譬如010相應的就是b,011相應的就是bc。code
僅僅需要從0到2^3-1作一個循環。而後把0-7之間的數用二進制表示出來,再與原集合進行對照。blog
把0相應位置的字符去掉,這樣就獲得了所有子集。ip
原理很是easy,如下是代碼字符串
package huisu; /** * Created by wolf on 2016/3/22. */ public class GetSet { private String[] origin = {"a", "b", "c"}; private String[] targetArray; public static void main(String[] args) { new GetSet().doJob(); } private void doJob() { //獲取將要分解的字符串假設轉爲2進制最大是幾 //如字符串是3位。就是2^3。在第23行是將10進制的0-7轉成二進制,轉以後例如如下圖從[0 0 0]到[1 1 1] int maxLength = (int) Math.pow(2, origin.length); targetArray = new String[maxLength]; for (int i = 0; i < targetArray.length; i++) { //十進制轉2進制 targetArray[i] = Integer.toBinaryString(i); } buling(); print(); } /** * 給空位補0,湊齊位數 */ private void buling() { for (int i = 0; i < targetArray.length; i++) { //位數是完整的,不需要補0 if (targetArray[i].length() == origin.length) { continue; } String temp = ""; //0,1,10,11,111 for (int j = 0; j < origin.length - targetArray[i].length(); j++) { temp += "0"; } targetArray[i] = temp + targetArray[i]; } } private void print(){ for (int i = 0; i < targetArray.length; i++) { String s = targetArray[i];//如000,001,010 for (int j = 0; j < s.length(); j++) { char item = s.charAt(j); if (item == '1') { System.out.print(origin[j]); } } System.out.println(); } } } get
這裏就有個問題,那就是位數並不滿。像0、10之類的,未來和原始數組作相應推斷的時候有點小麻煩,因此我作了個處理,把位數補齊。保持和原始數組位數同樣。
調用了buling(原諒我想不起來用什麼英語來表示補零)方法。把位數不足的前面全補上0.而後就變成了000,001,010……這樣就可以很是方便的去推斷了,僅僅打印1所在的位數便可了。參考print方法。
總結:這樣的作法比較簡單易懂。也能適應隨意長度的求子集問題。
依據這樣的作法,還能解決另一個問題——01揹包問題(有編號分別爲a,b,c,d,e的五件物品。它們的重量各自是2,2,6,5,4,它們的價值各自是6,3,5,4,6。現在給你個承重爲10的揹包。怎樣讓揹包裏裝入的物品具備最大的價值總和?)相信很是easy能看出來,上面的方法求出來了所有子集,那麼對於01揹包問題。就是依據所有的子集。先砍掉所有超重的子集。而後去計算剩餘的子集的價值,找到最大的就OK了。