일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- microflow
- git
- 자료구조
- Mendix
- 그래프
- 반효경교수님
- dfs
- Sort
- 이분탐색
- 정렬
- 재귀
- Bruteforce
- SQL
- 트리
- 완전탐색
- 알고리즘
- algorithm
- 멘딕스
- 백트래킹
- Recursion
- 가중치없는그래프
- 집합
- 매개변수 탐색
- lcap
- 해시맵
- domain model
- 스택
- MySQL
- 프로그래머스
- 자바
- Today
- Total
mondegreen
[240307] 알고리즘 리부트 26일차 - 백준 2295 자바 본문
[240307] 알고리즘 리부트 26일차 - 백준 2295 자바
앙갱 2024. 3. 7. 15:52[Part1-Chapter07-Clip03]
- 백준 2295 세 수의 합
문제를 읽고 제일 먼저 두 수를 고정하고 집합의 원소인 set[k] 에서 나머지 한 수를 이분탐색하는 방식을 고민했다. 하지만 코드를 작성하다 먼길을 가버렸고 한참을 단순히 l과 r의 범위나 m을 추출하는 방식을 고치면 탐색의 범위를 조정할 수 있지 않을까라는 바보 같은 생각을 했다.
코드를 작성하면서 l과 r을 다시 의사코드로 작성해보니 l과 r이 아니라 첫수와 두수를 투 포인터 방식으로 고정하고 나머지 한개의 수를 다시 배열에서 이분탐색했어야 했는데 라는 깨달음과 다시 코드를 의도에 맞게 작성했다. 그런데 테스트 케이스도 모두 맞추는데 이상하게 3%에서 틀리는 것이다....
결국 다른 코드를 참고해보니 결국 내가 작성한 것은 모든 경우의 수를 고려하고 있지 않았다. 첫번째 수와 두번째 수를 투포인터 방식으로 지정한다면 확인하지 못하는 조합이 생기는 것이다.
즉, 문제에서는 세 개의 수가 모두 같을 수 있다고 하는데 투포인터를 써버리면 모든 두개의 수 조합을 추출하지 못한다. 예를 들면 0, 1 ,2의 인덱스가 있다고 할 때, 00,01,02,11,12, 22와 같은 조합이 가능한데 투 포인터로 구하면 경우에 따라 02, 12, 22 / 02, 01, 11 / 02, 01, 00만 추출하고 마는 것이다. 그리고 당연히 3%에서 틀릴 수밖에.. 따라서 두 개의 수 조합을 모두 구해서 합을 내어 배열 또는 리스트에 담아두고(이 때 이 자료구조를 정렬하는 것을 잊지말기) 정답 후보가 될 k번째 수를 기준으로 나머지 세번째 수 후보(set[0]~set[n-1])를 뺀 값과 두 개의 수의 조합이 일치하는 경우를 이분탐색으로 찾으면 문제를 해결할 수 있다.
package BaekJoon.binarysearch;
import java.util.*;
public class BJ2295_1 {
public static int n;
public static int[] set;
public static void main(String[] args) {
input();
Arrays.sort(set);
List<Integer> twoSum = new ArrayList<>();
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
twoSum.add(set[i] + set[j]);
}
}
Collections.sort(twoSum);
int ansIdx = 0;
outer:
for (int k = n - 1; k >= 0; k--) {
for (int j = 0; j < n; j++) {
int target = set[k] - set[j];
int l = 0;
int r = twoSum.size() - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (twoSum.get(mid) == target) {
ansIdx = Math.max(k, ansIdx);
break outer;
} else if (twoSum.get(mid) > target) {
r = mid - 1;
} else {
l = mid + 1;
}
}
}
}
System.out.println(set[ansIdx]);
}
public static void input() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
set = new int[n];
for (int i = 0; i < n; i++) {
set[i] = sc.nextInt();
}
}
}
아래는 투포인터 방식으로 잘못 풀이한 코드이다.
package BaekJoon.binarysearch;
import java.util.Arrays;
import java.util.Scanner;
public class BJ2295 {
public static int n;
public static int[] set;
public static void main(String[] args) {
input();
Arrays.sort(set);
int ansIdx = -1;
outer:
for (int k = n - 1; k >= 0; k--) {
//System.out.println("k: " + k);
// 투포인터
int idxStart = 0;
int idxEnd = k - 1;
while (idxStart <= idxEnd) {
// System.out.println("첫번째 수:" + set[idxStart]);
// System.out.println("두번째 수:" + set[idxEnd]);
int target = set[k] - set[idxEnd] - set[idxStart];
// System.out.println("찾고자 하는 수:" + target);
if (target > 0) {
int l = 0;
int r = n - 1;
while (l <= r) {
int mid = (l + r) / 2;
// System.out.println("l: " + l);
// System.out.println("mid: " + mid);
// System.out.println("r: " + r);
if (set[mid] == target) {
ansIdx = k;
// System.out.println("찾았음");
break outer;
} else if (set[mid] > target) {
r = mid - 1;
} else {
l = mid + 1;
}
}
idxStart++;
//System.out.println("못찾아서 시작 수 하나 키움");
} else {
idxEnd--;
//System.out.println("숫자가 너무 커서 마지막 수 하나 줄임");
}
}
}
System.out.println(set[ansIdx]);
}
public static void input() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
set = new int[n];
for (int i = 0; i < n; i++) {
set[i] = sc.nextInt();
}
}
}
'알고리즘 풀이 및 리뷰 > [패캠] 핵심유형 20개로 한 번에 끝내는 알고리즘 코딩테스트 리뷰' 카테고리의 다른 글
[240311] 알고리즘 리부트 29일차 - 백준 2417 자바 (0) | 2024.03.11 |
---|---|
[240308] 알고리즘 리부트 27일차 - 백준 2470, 10816 자바 (0) | 2024.03.08 |
[240306] 알고리즘 리부트 25일차 - 백준 1920, 14425 자바 (0) | 2024.03.06 |
[240305] 알고리즘 리부트 24일차 - 백준 17232 자바 (1) | 2024.03.06 |
[240301] 알고리즘 리부트 21일차 - 백준 11659, 11660, 19951 자바 (0) | 2024.03.01 |