완전탐색 알고리즘에 대해 공부해보자.
모든 경우의 수를 탐색하여 결과를 찾아내는 방법이다.
모두 탐색하기 때문에 정답을 100% 찾아낼 수 있지만, 경우의 수에 따라 실행시간이 비례된다. 즉, 탐색 범위가 넓다면 그만큼 찾아내는 일을 해야하기 때문에 효율적이지 못할 수 있다.
function sequentialSearch (arr,x) {
for (let i = 0; i < arr.length; i++) {
if(arr[i] === x) {
return i;
}
}
return -1;
}
sequentialSearch([1,2,4,8,18,27,37],2);
순열과 함께 자주 나오는 개념으로, 서로 다른 n개 중 순서를 생각하지 않고 r개를 택할 때, 이것은 n개에서 r개를 택하는 조합이라 한다. 선택 순서는 상관없다(ex)[1,2] =[2,1])
-접근법
'1' 고정하고 -> 나머지 [2, 3, 4] 중에서 2개 조합
[1, 2, 3][1, 2, 4] [1, 3, 4]
'2' 고정하고 -> 나머지 [3, 4] 중에서 2개 조합
[2, 3, 4]
'3' 고정하고 -> 나머지 [4] 중에서 2개 조합
[]
'4' 고정하고 -> 나머지 [] 중에서 2개 조합
[]
'인셉션' 같다...
-코드
const getCombinations = (arr, selectNum) => {
const result = [];
if(selectNum === 1) {
return arr.map((el) => [el])
};
arr.forEach((fixed, idx, origin) => {
const rest = origin.slice(idx + 1);
// arr 배열에서 해당 fixed를 제외한 나머지 값
const combinations = getCombinations(rest, selectNum - 1);
// 현재 fixed를 제외한 나머지 숫자들을 재귀함수로 돌려 조합을 구한다.
const attached = combinations.map((combination) => [fixed,...combination]);
// 돌아온 조합에 떼어 놓은(fixed) 값 합치기
result.push(...attached);
})
return result;
}
getCombinations([1,2,3,4],3);
// output
[
[ 1, 2, 3 ],
[ 1, 2, 4 ],
[ 1, 3, 4 ],
[ 2, 3, 4 ]
]
❓ n개 중에 2개 뽑는 경우 구하기
-코드
const getPermutations = (arr, selectNum) => {
const result = [];
if(selectNum === 1) {
return arr.map((el)=> [el]);
}
arr.forEach((fixed, idx, origin) => {
const rest = [...origin.slice(0,idx), ...origin.slice(idx + 1)];
const permutations = getPermutations(rest,selectNum - 1 );
const attached = permutations.map((el) => [fixed,...el])
result.push(...attached);
})
return result;
}
getPermutations([1,2,3,4], 3);
// output
[
[ 1, 2, 3 ], [ 1, 2, 4 ],
[ 1, 3, 2 ], [ 1, 3, 4 ],
[ 1, 4, 2 ], [ 1, 4, 3 ],
[ 2, 1, 3 ], [ 2, 1, 4 ],
[ 2, 3, 1 ], [ 2, 3, 4 ],
[ 2, 4, 1 ], [ 2, 4, 3 ],
[ 3, 1, 2 ], [ 3, 1, 4 ],
[ 3, 2, 1 ], [ 3, 2, 4 ],
[ 3, 4, 1 ], [ 3, 4, 2 ],
[ 4, 1, 2 ], [ 4, 1, 3 ],
[ 4, 2, 1 ], [ 4, 2, 3 ],
[ 4, 3, 1 ], [ 4, 3, 2 ]
]
조합코드와 거의 똑같고, rest부분만 다르다.
|--- 현재 index보다 작으면 잘라낸다면, 조합
rest | fixed:1 => [2,3,4] => fixed:2 => [3,4] => ...
| fixed:2 => [3,4] => fixed:1 => [4] => ...
|--- 현재 index보다 작아도 존재해야한다면, 순열
fixed:1 => [2,3,4] => fixed:2 => [3,4] => ...
fixed:2 => [1,3,4] => fixed:1 => [3,4] => ...
❓ 나올 수 있는 전체 경우 구하기
const getPermutations = (arr) => {
const result = []; //(4) result = [[1,2]]
//(6) [1,2] => [2,1]
const swap = (arrToSwap, idxA, idxB) => {
const temp = arrToSwap[idxA];
arrToSwap[idxA] = arrToSwap[idxB];
arrToSwap[idxB] = temp;
};
const generate = (n , array) => {
//(3) n = 1이 되었기때문에, result에 담아줌
//(8) result에 [2,1] push
if(n === 1){
result.push([…array]);
return;
}
generate( n-1, array); //(2) n = 2, -> generate(1,[1,2])
//(5) 다시 g(2, [1,2])케이스로 돌아와서 for문을 탄다. n이 짝수이기 때문에 swap([1,2],0,1)
for(let i = 0; i < n - 1; i++) {
if(n % 2 === 0) {
swap(array, i, n - 1);
}else {
swap(array, 0, n - 1 );
}
generate( n - 1, array); //(7) generate(1, [2,1])
}
}
generate(arr.length, arr.slice()); //(1) generate 함수 호출 (2,[1,2])
return result;
}
getPermutations([1,2,3]);
이 방법은 순열의 경우의 수가 사전적으로 정렬되어 나오지 않는다.