from itertools import combinations
data = [1, 2, 3, 4]
# data에서 2개를 뽑는 모든 조합 구하기
result = list(combinations(data, 2))
print(result)
# 출력: [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
라이브러리를 사용할 수 없는 상황이나 조합의 원리를 이해해야 할 때는 백트래킹(Backtracking) 기법을 이용한 재귀 함수로 구현합니다.
이 코드는 start 인덱스를 이용해 이전에 선택한 요소 다음부터 탐색하도록 강제함으로써 순서를 무시하고 중복을 방지합니다.
def get_combinations(arr, n):
result = []
if n == 0:
return [[]]
for i in range(len(arr)):
elem = arr[i]
# 현재 원소(elem) 이후의 리스트(rest_arr)에서 n-1개를 뽑는 재귀 호출
rest_arr = arr[i + 1:]
for C in get_combinations(rest_arr, n - 1):
result.append([elem] + C)
return result
data = [1, 2, 3, 4]
print(get_combinations(data, 2))
# 출력: [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
import math
n = 5
k = 2
# 5개 중 2개를 뽑는 경우의 수 (5C2)
count = math.comb(n, k)
print(count)
# 출력: 10

1부터 N까지 모든 수로 나누어 떨어지는지 확인합니다. 이해하기 쉽지만 숫자가 크면 느립니다.
def count_divisors(n):
count = 0
for i in range(1, n + 1):
if n % i == 0:
count += 1
return count
print(count_divisors(15)) # 4
약수는 항상 짝꿍이 있다는 점을 이용합니다(예: ). 따라서 제곱근()까지만 검사하면 시간을 대폭 줄일 수 있습니다.
def count_divisors_fast(n):
count = 0
# 1부터 √n 까지만 반복
for i in range(1, int(n**0.5) + 1):
if n % i == 0:
count += 1 # i는 약수
if i != n // i: # 짝꿍 약수도 카운트 (예: 3이면 5도 카운트)
count += 1
return count
print(count_divisors_fast(15)) # 4
count +2count +2약수 자체를 구하고 싶다면 count 대신 리스트에 담으면 됩니다.
def get_divisors(n):
divisors = []
for i in range(1, int(n**0.5) + 1):
if n % i == 0:
divisors.append(i)
if i != n // i:
divisors.append(n // i)
return sorted(divisors) # 보기 좋게 정렬
print(get_divisors(15)) # [1, 3, 5, 15]
prefix는 앞에서부터 누적해서 더한 합을 저장한 배열이라서, 나중에 구간합을 아주 빠르게 구할 때 쓰는 도구입니다.
핵심은 prefix[r] - prefix[l]을 하면 원본 배열의 l부터 r-1까지의 합이 나온다는 점입니다.
예를 들어 elements = [7, 9, 1, 1, 4]라면, prefix는 보통 맨 앞에 0을 하나 두고 시작해서 [0, 7, 16, 17, 18, 22]처럼 만듭니다.
이 뜻은 prefix[1] = 7, prefix[2] = 7+9, prefix[3] = 7+9+1처럼 0번부터 그 직전까지의 합을 저장해 둔 것이라고 보면 됩니다.
예를 들어 원본 배열에서 인덱스 1부터 3까지의 합, 즉 9 + 1 + 1 = 11을 구하고 싶다면 prefix[4] - prefix[1]을 하면 됩니다.
실제로 prefix[4]는 7+9+1+1=18이고, prefix[1]은 7이므로 18 - 7 = 11이 되어 앞부분이 깔끔하게 빠집니다.
👉 2부터 √n까지만 나눠본다
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n**0.5) + 1):
if n % i == 0:
return False
return True
약수는 항상 쌍으로 존재:
n = a × b
예:
36 = 6 × 6
36 = 4 × 9
👉 작은 쪽만 보면 큰 쪽은 자동으로 결정됨
👉 그래서 √n까지만 확인하면 충분
n < 2 → 소수 아님
| 값 | 결과 |
|---|---|
| 0 | ❌ |
| 1 | ❌ |
| 2 | ✅ |
| 방법 | 복잡도 |
|---|---|
| 2 ~ n | O(n) ❌ |
| 2 ~ √n | O(√n) ✅ |
👉 무조건 √n 버전 사용
👉 개별 판별 말고 체(에라토스테네스) 사용
def sieve(n):
prime = [True] * (n+1)
prime[0] = prime[1] = False
for i in range(2, int(n**0.5)+1):
if prime[i]:
for j in range(i*i, n+1, i):
prime[j] = False
return prime
n < 2 처리👉 “나눠떨어지는 순간 탈락, √n까지만 보면 된다”