Notion에서 작성한 글이라, 여기에서 더 깔끔하게 보실 수 있습니다! 😮😊
문제를 푸는 방법은 크게 아래의 두 단계로 나뉜다.
from itertools import permutations
p
를 단순히 append
해주면 참조가 계속 append
되어서, p
가 변경될 때마다 ret
에 저장된 모든 값들이 동일하게 변경되는 문제가 발생했다. Shallow Copy로 해결했다.def permutations(iterable, r):
p = [0]*r
used = [False]*len(iterable)
ret = []
def _perm(k):
if k == r:
ret.append(p[:])
return
for i in range(len(iterable)):
if not used[i]:
p[k] = iterable[i]
used[i] = True
_perm(k+1)
used[i] = False
_perm(0)
return ret
numbers
의 각 자리가 unique하지 않을 때)numbers
의 각 자리가 unique하지 않을 때 더 빠르다.numbers
의 길이가 7이고, 각 자리가 unique해서 순열 생성 시 중복되는 숫자가 나오지 않는 경우이다. 이므로 인데, 각 숫자가 소수인지 판별하는 데에 최악의 단 한 경우에서만 이고, 이후 까지 줄어들게 되므로 실제 시간복잡도는 훨씬 낮다고 볼 수 있다.numbers
를 이용하여 만들 수 있는 가장 큰 수까지의 소수 목록을 만들어 놓으면, 각 수에 대해 로 판별할 수 있게 된다.numbers
가 '9999999'
인 경우이다. 이 때 소수 목록을 만드는 데 이 소요되고, 각 수에 대해 로 판별하므로 이다.소수 판별
def isprime(x):
if x <= 1: return False
for i in range(2, x):
if x%i == 0: return False
return True
소수 판별
def isprime(x):
if x <= 1: return False
for i in range(2, int(x**.5)+1):
if x%i == 0: return False
return True
Proof.
자연수 을 (, 와 는 과 이 아닌 자연수) 를 만족하는 합성수라고 하자.
이므로 이고 이다. (∵ )
따라서 의 최솟값이자 의 최댓값은 이 되므로, 까지만 확인하면 이 소수인지 아닌지 판별할 수 있다.
소수 판별
def isprime(x):
if x <= 1: return False
if x <= 3: return True
if x%2 == 0 or x%3 == 0: return False
i = 5
while i*i <= x:
if x%i == 0 or x%(i+2) == 0: return False
i += 6
return True
while i*i <= x:
때문에 구간 에서 소수를 정확히 판별하지 못하는 경우가 발생한다. (while문을 수정해주면 되긴 한다.)Miller-Rabin 소수 판별
def isprime(x):
if x <= 1: return False
if x <= 3: return True
if x%2 == 0 or x%3 == 0: return False
i = 5
while i*i <= x:
if x%i == 0 or x % (i+2) == 0: return False
i += 6
return True
def solution(numbers):
checked = set()
for n in range(1, len(numbers)+1):
perm = permutations(numbers, n)
for p in perm:
num = int(''.join(p))
if num not in checked and isprime(num):
checked.add(num)
return len(checked)
permutations
를 통해 만들어진 어떤 수는, 위에서 서술했듯 중복된 값이 존재할 수 있다. 따라서 계산했던 값은 set에 저장해놓고, 매 수에 대해 이미 계산했던 값은 아닌지 Amortized 에 확인한 다음 소수 판별을 진행하는 방법으로 최적화했다.8.36ms, 10.4MB
, TC #8에서 6.51ms, 10.4MB
의 결과가 나왔다.def get_primes(num):
n = int(''.join(sorted(num, reverse=True)))
primes = [True]*(n+1)
primes[0] = primes[1] = False
for i in range(2, int(n**.5)+1):
if primes[i]:
j = 2
while i*j <= n:
primes[i*j] = False
j += 1
return primes
def solution(numbers):
checked = set()
primes = get_primes(numbers)
for n in range(1, len(numbers)+1):
perm = permutations(numbers, n)
for p in perm:
num = int(''.join(p))
if primes[num]: checked.add(num)
return len(checked)
primes
를 만들어 놓고, permutations
를 통해 만들어진 어떤 수에 대해 소수인지 에 판별한다.1039.46ms, 35.5MB
, TC #8에서 1816.67ms, 52.5MB
의 결과가 나왔다.def get_primes(num):
n = int(''.join(sorted(num, reverse=True)))
sieve = [True]*(n+1)
for i in range(3, int(n**.5)+1, 2):
if sieve[i]: sieve[i*i::2*i] = [False]*len(sieve[i*i::2*i])
return {2} | {i for i in range(3, n+1, 2) if sieve[i]}
def solution(numbers):
primes = get_primes(numbers)
ret = set()
for i in range(1, len(numbers)+1):
perm = permutations(numbers, i)
for p in perm:
num = int(''.join(p))
if num in primes: ret.add(num)
return len(ret)
245.24ms, 65.7MB
, TC #8에서 468.14ms, 105MB
의 결과가 나왔다.