[Java] 43165 타겟 넘버
1. 문제
타겟 넘버

2. 접근 방법
- 각 숫자마다 연산자로 두 가지 선택지가 있다. → + 또는 -
- DFS로 모든 경우를 탐색하면서 합계를 누적한다.
- 모든 숫자를 다 사용한 시점은 (depth == numbers.length)에 합이 target과 같으면 count++;
3. 정답 코드
DFS
class Solution {
int answer = 0;
public int solution(int[] numbers, int target) {
dfs(numbers, target, 0, 0);
return answer;
}
private void dfs(int[] numbers, int target, int depth, int sum) {
// 모든 숫자를 다 사용했을 때
if (depth == numbers.length) {
if (sum == target) {
answer++;
}
return;
}
//현재 숫자 더하는 경우
dfs(numbers, target, depth + 1, sum + numbers[depth]);
// 현재 숫자를 빼는 경우
dfs(numbers, target, depth + 1, sum - numbers[depth]);
}
}
return
if (depth == numbers.length) {
if (sum == target) {
answer++;
}
return;
}
1. 모든 숫자를 다 사용했을 때 (depth == numbers.length)
→ 이제 더 이상 탐색할 숫자가 없으니까 여기서 탐색을 종료해야 한다.
2. 합이 target 과 같으면 answer++
3. 여기서 조건 검사가 끝났으면 더 내려갈 재귀 호출이 없으니까 return;으로 그냥 메서드를 끝내는 것이다. 만약에 return을 안 하면 dfs(..., sum + numbers[depth]) 같은 코드로 내려가려 하기 때문에, 불필요하게 실행되거나 ArrayIndexOutOfBounds 에러가 날 수 있다.)
- return; = 현재 메서드 즉시 종료 (값은 반환하지 않음)
- return 값; = 현재 메서드 즉시 종료 + 값을 반환
return 없으면?
private void dfs(int[] numbers, int target, int depth, int sum) {
if (depth == numbers.length) {
if (sum == target) {
answer++;
}
// return 없음
}
dfs(numbers, target, depth + 1, sum + numbers[depth]); // 계속 실행됨
dfs(numbers, target, depth + 1, sum - numbers[depth]);
}
BFS
import java.util.*;
class Solution {
public int solution(int[] numbers, int target) {
int answer = 0;
Queue<int[]> queue = new LinkedList<>();
// {현재까지 합, depth}
queue.add(new int[]{0, 0});
while (!queue.isEmpty()) {
// 큐가 빈 것이 아니라면
int[] current = queue.poll();
int sum = current[0];
int depth = current[1];
// 모든 숫자를 다 사용했으때
if (depth == numbers.length) {
if (sum == target) {
answer++;
}
} else {
// 현재 숫자를 더하는 경우
queue.add(new int[]{sum + numbers[depth], depth + 1});
// 현재 숫자 빼는 경우
queue.add(new int[]{sum - numbers[depth], depth + 1});
}
}
return answer;
}
}
queue에 담는 원소는 두 가지 정보이다.
- sum = 지금까지 만든 합
- depth = 몇 번째 숫자까지 썼는지
처음에는 아직 아무 숫자도 사용하지 않았고, 합계도 0이기 때문에 {0, 0} 으로 초기화한다.
while (!queue.isEmpty()) {
// 큐가 비어있지 않다면 하나 꺼내기
int[] current = queue.poll();
int sum = current[0];
int depth = current[1];
모든 숫자를 다 사용했을 때(depth == numbers.length) 라면 더 이상 확장하지 못한다. 그 시점의 합이 target과 같으면 answer++로 경우의 수 1개를 추가해준다.
아직 탐색할 숫자가 남아 있다면
- sum에+numbers[depth]한 새로운 합을 큐에 넣고
- sum에 -numbers[depth]한 새로운 합을 큐에 넣는다.
그래서 큐에는 매 단계에서 앞 숫자를 “더한 경우”와 “뺀 경우” 두 가지 상태가 들어가게 되고, 결국 배열 안에 있는 모든 숫자를 다 쓸 때까지 앞전 합계에 그다음 숫자를 더한 경우와 뺀 경우로 가지치기처럼 계속 분기해서 모든 경우의 수를 탐색하는 것이 된다.
// 현재 숫자를 더하는 경우
queue.add(new int[]{sum + numbers[depth], depth + 1});
// 현재 숫자를 빼는 경우
queue.add(new int[]{sum - numbers[depth], depth + 1});
이렇게 하면 모든 경우가 큐 안에서 너비 우선으로 탐색된다.