1. 程式人生 > >【算法】—— 集合的子集

【算法】—— 集合的子集

位置 當前 i+1 += 一種可能 個數 理解 function clas

問題

給定一個集合,輸出它的所有子集。

示例:

給定集合{1,2,3},應該輸出:

{}

{1}

{2}

{1, 2}

{3}

{1, 3}

{2, 3}

{1, 2, 3}

解法1:增量構造法

增量構造法,每次選擇一個元素放到集合中,每次操作的結果即是一個子集。

遞歸操作,每次向當前集合中添加一個比當前集合中最大的元素大1的數。

from __future__ import print_function
 
def print_subset(n, lst, cur):
    for i in range(cur):
        print(lst[i]+1, end=‘‘
) print() if cur: s = lst[cur - 1] + 1 else: s = 0 for i in range(s, n): lst[cur] = i print_subset1(n, lst, cur+1)

解法2:位向量法

構造位向量(可理解為構造一個數組),該向量中的每一位置可以取0值或者1值,0和1分別代表該位置上對應的值是否在集合中。如向量為[1, 0, 0, 1],其第1和4位上有1,所以該向量表示的集合為{1, 4}。

思路:
如果需要用向量來表示集合,那麽需要保證向量的每一種變化能夠剛好覆蓋集合的每一種可能性。

對n求子集,構造長度為n的向量,每一位可以代表取或者不取該位置的值,共有2^n中可能。

from __future__ import print_function
 
def print_subset(n, lst, cur):
    if cur == n:
        for i in range(n):
            if lst[i]:
                print(i+1, end=‘‘)
        print()
    else:
        lst[cur] = 0
        print_subset(n, lst, cur
+1) lst[cur] = 1 print_subset(n, lst, cur+1)

解法3:二進制法

我們可以使用二進制法來表示子集。對於n求子集,其子集有2^n個(包括空集),比如n = 4,其有16個子集,這16個子集用二進制可以表示成:

0->0000->{}
1->0001->{1}
2->0010->{2}
3->0011->{1,2}
4->0100->{3}
5->0101->{1,3}
...
15->1111->{1,2,3,4}

思路:

求n的子集,可以依次處理1到2^n - 1之間的每一個數,每個數取出它二進制表示中的1的位置,以此表示該數對應的集合。比如5,二進制表示的後四位為0101,其在第1和第3位處有1,那麽,其代表的集合為{1, 3}。使用位運算中與(&)操作,可以方便的求出二進制某位置上是否為1。

from __future__ import print_function
s = 1
n = 4
while s < (1 << n):  # 依次遍歷1到2^n - 1之間的每一個數
    for i in range(n):  # 每一個數使用&操作判斷該位置上是否有1,有打印或者保存起來
        if s & (1 << i):
            print(i+1, end=‘‘)
    print()
    s += 1

【算法】—— 集合的子集