백준이나 프로그래머스에서 문제를 풀다보면 부분집합을 구했을때 굉장히 쉽게 풀 수 있는 문제들이 있습니다. 매번 itertools라는 라이브러리를 사용해서 해결했었는데 그마저도 기억이 안나서 구글링해서 해결한 적이 많죠.. 오늘은 이런 사태를 예방하기 위해, 내용도 제대로 숙지할 겸, 제 블로그에 정리해보겠습니다. 먼저 코드를 보여주고 해당코드에 대해 설명해보겠습니다^^
파이썬에서 부분집합을 구하는 방법은 여러 가지가 있습니다. 그 중 가장 대표적인 방법 4가지를 소개하고 구현해보겠습니다.
- itertools 라이브러리의 combinations 메서드 사용하기
- 단순 반복문과 배열
- 재귀
- 비트연산
from itertools import combinations
arr = [1, 2, 3]
result = []
for i in range(len(arr)+1):
result = result+list(combinations(arr,i))
print(result)
# [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
가장 직관적으로 이해되는 방법이어서 평소에 가장 많이 사용해왔던 방법입니다. itertools라는 라이브러리에 있는 combinations를 사용한 방법입니다. combinations의 사용방법은 아래와 같습니다.
from itertools import combinations
arr = [1,2,3]
print(list(combinations(arr,1)))
#[(1,), (2,), (3,)]
print(list(combinations(arr,2)))
#[(1, 2), (1, 3), (2, 3)]
combinations 메서드의 첫번째 인자로 대상 리스트를 넣고,
두번째 인자로는 부분집합의 길이를 넣는다.
=> 해당 길이를 가지는 부분집합
메서드에서 나왔을 때는 combinations 객체라는 형태로 있기 때문에 list 메서드로 형변환을 해주어야만 리스트로 사용할 수 있습니다.
공집합을 포함한 모든 부분집합을 구하려면 두번째로 들어갈 인자의 값을 배열의 길이를 모두 커버할때까지 1씩 더하면서 result 배열에 더해주면 됩니다!
arr = [1, 2, 3]
subsets = [[]]
for num in arr:
size = len(subsets)
for y in range(size):
subsets.append(subsets[y]+[num])
print(subsets)
import copy
result = []
def recur(subset, i, arr):
if i == len(arr): # 재귀함수의 탈출조건
result.append(copy.copy(subset)) # 결과에 들어가는 모든 원소에 해당하는 부분집합의 레퍼런스가
return # subset으로 같기 때문에 subset을 카피하여 넣어줘야 한다.
# 이렇게 하지 않으면 result에 들어가는 모든 부분집합이 공집합으로 나온다.
else:
subset.append(arr[i])
i += 1
recur(subset, i, arr) # i번째 원소가 '있을' 때의 경우에서 분화
subset.pop()
recur(subset, i, arr) # i번째 원소가 '없을' 때의 경우에서 분화
recur([], 0, arr)
print(result)
arr = [1,2,3]
result = []
for i in range(1<<len(arr)):
subset = []
for j in range(len(arr)):
if i & (1<<j):
subset.append(arr[j])
result.append(subset)
print(result)
000, 001, 010, 011, 100, 101, 110, 111
000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
---|---|---|---|---|---|---|---|
001 | 001 | 001 | 001 | 001 | 001 | 001 | 001 |
010 | 010 | 010 | 010 | 010 | 010 | 010 | 010 |
100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 |
[] | [1] | [2] | [1,2] | [3] | [1,3] | [2,3] | [1,2,3] |
itertools : 0.6088559627532959
단순 반복문 : 1.1612977981567383
재귀함수 : 1.6987059116363525
비트연산 : 5.907625913619995
잘 읽었어요 감사합니다!