너비 우선탐색과 깊이 우선탐색을 이용하면 이러한 것들을 구현할 수 있습니다.
cf. DFS BFS 깊이 너비 우선탐색 알고리즘 5분만에 이해하기
- 드라마 하나를 몰아본다 = DFS
- 드라마 여러 개를 하나씩 본다 = BFS
그래프 탐색 알고리즘 = BFS, DFS
그래프: 여러 개체들이 연결되어 있는 자료구조탐색: 특정 개체를 찾기 위한 알고리즘
| DFS | BFS | |
|---|---|---|
| 수행시간 | 복불복 | 모든 경우의 수를 한 걸음씩 나감 |
| 운이 좋으면 첫번째 조합이 최적의 답 최악의 경우 모든 조합을 다 만들어야 함 | 초반에 느리더라도 하나의 정답만 찾으면 나머지 경우의 수는 정답에서 제외 | |
| 시간복잡도 | 높다 | 낮다 |

BFS (Breadth-First Search, 너비 우선 탐색)
DFS (Depth-First Search, 깊이 우선 탐색)
최상위 노트에서 연결된 자식 노드를 모두 탐색한 후, 더 이상 자식 노드가 없을 때 인접한 상위 노드의 형제 노드를 방문,
해당 형제 노드에서도 자식 노드를 탐색하고, 더 이상 자식노드가 없을 경우 다시 인접한 상위 형제의 노드를 방문
코딩테스트 고득점 Kit : 프로그래머스 Level 2 타겟넘버
경우의 수 계산 : 최악의 경우 수행할 연산 횟수를 계산해 재귀함수/완전탐색을 사용할지 확인수행동작 : 재귀함수가 호출됐을 떄 1턴마다 수행할 동작 구현탈출조건 : 어느 시점에 이 재귀함수를 끊을지 구현numbers의 0번째 부터 마지막까지 모든 요소를 각각 덧셈 또는 뺄셈한 결과를 모두 확인하여 target과 같은 경우의 개수를 세기
/** https://school.programmers.co.kr/learn/courses/30/lessons/43165?language=javascript
* numbers 배열을 각각 더하거나 빼서 목표하는 target 숫자 만드는 모든 경우의 수 구하기
* @param {*} numbers 사용할 수 있는 숫자
* @param {*} target 타겟 넘버
* @returns target 숫자 만드는 모든 경우의 수
* numbers의 각 자리의 숫자를 더하거나 빼는 경우가 2
* 주어지는 숫자 최대 개수가 20개
* 그 20개의 숫자에 대해 각각 2가지 경우의 수가 존재
* 2의 20승인 100만번 정도가 최악의 경우의 수
*/
function solution(numbers, target) {
let answer = 0;
const length = numbers.length;
DFS(0, 0); //함수 호출 (0번째 숫자, 현재까지 합계 0)
return answer;
// numbers의 인덱스와 현재까지의 합계
function DFS(index, sum) {
// **** 1. 탈출 조건
// numbers의 인덱스를 모두 탐색했다면
if (index === length) {
// 현재까지의 합계가 target이면 answer++
if (target === sum) {
answer++;
}
return;
}
// **** 2. 수행동작
// 모든 숫자가 (+)인 경우를 모두 탐색한 뒤
// 다음 인덱스의 숫자가 (-)인 경우를 탐색
DFS(index + 1, sum + numbers[index]);
DFS(index + 1, sum - numbers[index]);
}
}
numbers는 [1,1,1,1,1]이, target이 3인 경우

(1) DFS(index + 1, sum + numbers[index]) 부분이 계속 실행되며 다음 인덱스의 숫자가 (+) 인 자식 노드를 계속 탐색

(2) 마지막 인덱스에 다다랐을 경우(index = 5, sum = 5 일 때) 해당 함수를 스택에서 제거한 뒤,
index가 4일 때 DFS(index + 1, sum - numbers[index]) 을 실행하여 (-)인 자식 노드를 탐색

(3) 마지막 인덱스에 다다랐으니 다시 해당 함수를 스택에서 제거,
index가 3일 때 DFS(index + 1, sum — numbers[index]) 을 실행

(4) index 4가 (-)일 때 DFS(index + 1, sum + numbers[index])을 실행하여 index 5가 (+)인 경우의 자식을 탐색,
탐색을 마치면 해당 함수를 스택에서 제거한 뒤
DFS(index + 1, sum - numbers[index])을 실행하여 index 5가 (-)인 경우의 자식을 탐색
(5) 다시 index가 2일 때 DFS(index + 1, sum + numbers[index])을 실행,
index 3이 (-)일 때 DFS(index + 1, sum + numbers[index])을 실행하여 index 4가 (+)인 경우의 자식 노드를 모두 탐색 후
15번 라인을 실행하며 index 5가 (-)인 경우의 자식 노드를 탐색
(+)의 자식 노드 탐색 → (-)의 자식 노드 탐색 순서로 위 과정이 진행되며,
index 1이 (-)일 때의 자식 노드의 경우의 수 (+), (-) 를 모두 탐색하면 해당 함수가 종료
/** https://school.programmers.co.kr/learn/courses/30/lessons/43165?language=javascript
* numbers 배열을 각각 더하거나 빼서 목표하는 target 숫자 만드는 모든 경우의 수 구하기
* @param {*} numbers 사용할 수 있는 숫자
* @param {*} target 타겟 넘버
* @returns
* numbers의 각 자리의 숫자를 더하거나 빼는 경우가 2
* 주어지는 숫자 최대 개수가 20개
* 그 20개의 숫자에 대해 각각 2가지 경우의 수가 존재
* 2의 20승인 100만번 정도가 최악의 경우의 수
*/
function solution(numbers, target) {
function DFS(index, sum) {
if (index === numbers.length) return sum === target ? 1 : 0;
return DFS(index + 1, sum + numbers[index]) + DFS(index + 1, sum - numbers[index]);
}
return DFS(0, 0);
}
코딩테스트 고득점 Kit : 프로그래머스 Level 2 게임 맵 최단거리
function solution(maps) {
let answer = -1;
const X_LEN = maps.length; // maps의 행
const Y_LEN = maps[0].length; // maps의 열
const DIRECTION = [
[1, 0], // 상
[0, 1], // 우
[-1, 0], // 하
[0, -1], // 좌
];
// // BFS에 사용할 queue를 생성
const mapsQueue = [];
maps[0][0] = 0; // 시작 위치
// 첫 시작은 무조건 가장 좌측의 가장 상단에서 시작하므로
// 0, 0 좌표와 이동한 칸 수 까지 해서 [0, 0, 1]
mapsQueue.push([0, 0, 1]);
while (mapsQueue.length > 0) {
const [x, y, distance] = mapsQueue.shift();
if (x === X_LEN - 1 && y === Y_LEN - 1) {
answer = distance;
break;
}
for (let i = 0; i < DIRECTION.length; i++) {
const [nextX, nextY] = [x + DIRECTION[i][0], y + DIRECTION[i][1]];
if (nextX < 0 || nextX >= X_LEN || nextY < 0 || nextY >= Y_LEN || maps[nextX][nextY] === 0) {
continue;
}
maps[nextX][nextY] = 0;
mapsQueue.push([nextX, nextY, distance + 1]);
}
}
return answer;
}