바위타는 두루미

8.4 부분집합 본문

Study/Interview준비

8.4 부분집합

DoRoMii 2019. 8. 4. 18:54
728x90

문제 

어떤 집합의 부분집합을 전부 반환하는 메서드를 작성하라

 

해결법

우선 시간복잡도와 공간복잡도를 한번 알아보자

한 집합의 부분집합은 얼마나 될까? n개의 원소가 있다고 할때 그 부분집합에 있거나, 없거나 2가지 경우에 대한 경우의 수이기 때문에 2^n개이다. 그렇다면 모든 부분집합의 리스트를 반환하는 경우에는 공간이 얼마나 차지할까? 각 원소는 전체 부분집합에 1/2에 속하게 된다. 그러면 각 원소들은 2^(n-1)개씩 존재할 것이고 원소의 갯수를 n이라고 하면 n * 2^(n-1)의  공간복잡도를 차지하게 될 것이다. 

 

1. 재귀적으로 해결하기

 이 문제는 초기사례로부터의 확장을 적용하기 좋은 문제이다. 

S = { a1, a2, a3 ...} 라고 했을때 

a1을 가지고 만들 수 있는 부분집합  : {} ,{a1}

a1, a2를 가지고 만들 수 있는 부분집합 :  {} ,{a1}, {a2} ,{a1,a2}

a1, a2, a3를 가지고 만들 수 있는 부분집합 : {} ,{a1}, {a2}, {a3} ,{a1,a3}, {a2,a3}  ,{a1,a2} ,{a1,a2,a3}

a2까지의 부분집합과 a3까지의 부분집합의 차이를 보면 기존의 부분집합들에 a3가 포함된 집합들이 추가 되었다.

이 규칙을 보면 P(n-1)까지 만들고나서 그 결과를 복사해서 an을추가하면 P(n)이 되는 것을 알 수 있다. 

def Solution(array):
    return getSubsets(array, 0)

def getSubsets(array, i):
    if (len(array)-1) == i :
        return [[],[array[i]]]
    
    prev_sets = getSubsets(array, i+1)
    new_sets = list(prev_sets)
    for j in range(len(new_sets)):
        new_sets[j].append(array[i])

    return prev_sets + new_sets

2. 조합론으로 해결하기

모든 경우의 수는 2^n개가 존재한다고 하였다. 그말은 각각의 원소에 대해 집합에 속하는지, 속하지 않는지 두가지 선택을 할 수 있고 따라서 각 부분집합은 모든 요소들에 대해 {'yes','yes','no','no'} 이런식으로 표현될 수 있다.

따라서 모든 부분집합을 만들어 내는것은 사실 이진수를 만들어 내는 것과 같다. 1부터 2^n까지의 모든 정수의 이진 표현을 집합으로 표현하면 된다. 

def Solution(array):
    subsets = []
    max = 1 << len(array)
    for i in range(max):
        subsets.append(getNumtoSubset(i, array))
    return subsets


def getNumtoSubset(k, array):
    subset =[]
    i = 0
    while k > 0:
        if k & 1 == 1:
            subset.append(array[i])
        i +=1
        k >>=1
    return subset

'Study > Interview준비' 카테고리의 다른 글

8.6 하노이타워  (0) 2019.08.04
8.5 재귀 곱셈  (0) 2019.08.04
8.3 마술인덱스  (0) 2019.08.04
8.1 트리플 스텝  (0) 2019.08.04
[개념정리] 수학 및 논리 퍼즐  (0) 2019.08.04
Comments