코딩테스트를 하며 자주 쓰게 되는 간단한 알고리즘을 공부했다.
외우면 빠르게 적용가능하다고 생각해 TIL에 정리해보기로 했다.
오늘은 재귀를 통해 특정 배열과 원소개수가 주어졌을 때, 순열과 조합을 출력하는 코드를 작성해보았다.
순열이란 순서를 정해 나열한 것을 의미한다.
nPr = n (n-1) … * (n-r+1)
nPn = n!
순열 알고리즘을 재귀로 구현했을 때, 시간복잡도는 O(N!)
function getProduct(arr, k) {
if (k === 0) return [[]];
const result = [];
const prev = getProduct(arr, k - 1);
for (const p of prev) {
for (const a of arr) {
result.push([...p, a]);
}
}
return result;
}
[예시]
getProduct([10,20,30], 1)
을 호출getProduct([10,20,30], 0)
을 호출getProduct([10,20,30], 0)
은 [[]]
을 return하고 이 값은 prev가 됨.[]
하나이므로, arr의 각 a가 result에 push된다. [[10], [20], [30]]
을 리턴한다.3(prev)*3(arr)
, 9개를 리턴하고 종료한다.[
[ 10, 10 ], [ 10, 20 ],
[ 10, 30 ], [ 20, 10 ],
[ 20, 20 ], [ 20, 30 ],
[ 30, 10 ], [ 30, 20 ],
[ 30, 30 ]
]
조합은 순열과 다르게 순서를 정하지 않고 나열한 것을 의미한다.
nCr = n! / (n-r)! (r)!
시간복잡도는 O(2^n)
function getCombinations(arr, k) {
if (k === 0) return [[]];
if (k > arr.length) return [];
const result = [];
for (let i = 0; i < arr.length; i++) {
const head = arr[i];
const prev = getCombinations(arr.slice(i + 1), k - 1);
for (const p of prev) {
result.push([head, ...p]);
}
}
return result;
}
[예시]
head[i]
가 10일 때getCombination([20,30], 1)
을 호출getCombination([30], 0)
을 호출[[]]
으로 for문을 진행한다. 그 뒤 [[20],[30]]
리턴한다.[[20],[30]]
으로 for문을 진행한다. 이후 result에 head를 추가한[10,20]
와 [20,30]
를 추가한다.head[i]
가 20일 때getCombination([30],1)
을 호출한다.[[30]]
를 리턴하고 다시 for문 진행[20,30]
을 result에 추가한다. head[i]
가 30일 때getCombination([],1)
을 호출한다.[
[ 10, 20 ],
[ 10, 30 ],
[ 20, 30 ]
]