Given two integer arrays arr1 and arr2, and the integer d, return the distance value between the two arrays.
The distance value is defined as the number of elements arr1[i] such that there is not any element arr2[j] where |arr1[i]-arr2[j]| <= d.
Example 1:
Input: arr1 = [4,5,8], arr2 = [10,9,1,8], d = 2
Output: 2
Explanation:
For arr1[0]=4 we have:
|4-10|=6 > d=2
|4-9|=5 > d=2
|4-1|=3 > d=2
|4-8|=4 > d=2
For arr1[1]=5 we have:
|5-10|=5 > d=2
|5-9|=4 > d=2
|5-1|=4 > d=2
|5-8|=3 > d=2
For arr1[2]=8 we have:
|8-10|=2 <= d=2
|8-9|=1 <= d=2
|8-1|=7 > d=2
|8-8|=0 <= d=2
Example 2:
Input: arr1 = [1,4,2,3], arr2 = [-4,-3,6,10,20,30], d = 3
Output: 2
Example 3:
Input: arr1 = [2,1,100,3], arr2 = [-5,-2,10,-3,7], d = 6
Output: 1
<전체 코드1>
1. 부루트포스 방식
class Solution {
public int findTheDistanceValue(int[] arr1, int[] arr2, int d) {
int count = 0;
for(int a : arr1){
boolean isValid = true;
for(int b : arr2){
if(Math.abs(a-b) <= d){
isValid = false;
break;
}
}
if(isValid){
count++;
}
}
return count;
}
}
흠냐 너무 어렵게 생각함.
arr1 순회하고 그 안에서 arr2 순회하면서 배열 내부 정수들 비교하면 된다.
브루트포스 방식은 쉽게 말하면 가능한 모든 경우를 전부 다 시도해서 값을 찾는 방식이다.
**중요
Math.abs(a-b)
- a와 b 사이의 절댓값 거리를 의미함.
- Math.abs(-5) = 5
이런 식으로 절댓값을 붙여서 값을 리턴함.
위의 문제에서는 거리를 물어봤기 때문에 Math.abs(a-b)를 사용해서 구하면 된다!
<전체 코드2>
2. 이진 탐색 방식
import java.util.Arrays;
public class Solution {
public int findTheDistanceValue(int[] arr1, int[] arr2, int d) {
Arrays.sort(arr2); // 이진 탐색을 위해 정렬
int count = 0;
for (int a : arr1) {
if (!hasCloseElement(arr2, a, d)) {
count++;
}
}
return count;
}
// arr2에서 a와 |a - arr2[j]| <= d인 원소가 있는지 이진 탐색으로 확인
private boolean hasCloseElement(int[] arr2, int a, int d) {
int left = 0, right = arr2.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
int diff = Math.abs(arr2[mid] - a);
if (diff <= d) return true;
if (arr2[mid] < a) left = mid + 1;
else right = mid - 1;
}
return false;
}
}
1) Arrays.sort(arr2);
- 우선 이진 탐색을 위해 정렬을 하고,
2) for (int a : arr1) {
if (!hasCloseElement(arr2, a, d)) {
count++;
}
}
- arr1 의 원소를 하나 꺼내서 함수로 ㄱㄱ
[ 이진 탐색 과정 ]
3) int left = 0, right = arr2.length - 1;
- 왜 right 가 arr2.length-1 인가?
> 처음에는 양 끝 인덱스로 시작하는데, 인덱스는 0부터 시작하므로 길이 -1을 해야 끝 인덱스임.
4)
while (left <= right) {
int mid = left + (right - left) / 2;
int diff = Math.abs(arr2[mid] - a);
- 왜 int mid = left + (right - left) / 2; 이렇게 하지?
**중요
만약 left = 2_000_000_000;
right = 2_000_000_010; 일 때
left+right는 4_000_000_010이 돼서 int 범위를 넘을 수도 있음.
근데, right - left는 차이값이기 때무에 절대 크지 않음.
-> 무슨 말이냐면, 배열이 아주 크더라고 각 반복마다 절반씩 범위를 줄여가기 때문에 right-left는 바르게 줄어든다.
!! 즉, 정수 오버플로우 위험
을 방지하기 위해서 i nt mid = left + (right - left) / 2 이렇게 함.
4.1)
int diff = Math.abs(arr2[mid] - a);
- arr2[mid]와 a를 비교하는 이유는 둘이 얼마나 가까운지 확인하기 위함임.
- 즉, arr2가 정렬되어 있기 때문에 이진 탐색을 사용해서 arr2의 중간값부터 빠르게 비교할 수 있음.
예시:
arr1 = [4, 5, 8], arr2 = [10, 9, 1, 8], d = 2일 때
arr2 = [1, 8, 9, 10] -> arr2 정렬.
a = 4 에 대해서 arr2의 중간값인 9와 비교해보면 d보다 큼
-> 그러면 9보다 큰 숫자에 대해서 비교할 필요가 없어지는 것임. d 보다 무조건 클 것이기 때문에
그래서 right를 -1해가며 비교해서 빠르게 구할 수 있음.
5)
if (diff <= d) return true; // 거리가 d 이하이면 조건에 안 맞는 거 → true 반환
- !hasCloseElement(arr2, a, d)일 때 count++이므로 diff <=d 일때는 count 안하기 때문에 true를 반환하면 false이므로 count를 안 하게 되니까 .. true를 반환함.
-> 이렇게 조건을 반대로 처리하는 방식이 코드의 흐름을 더 간단하고 직관적으로 만들어 준다는 장점이 있음.
6)
if (arr2[mid] < a) left = mid + 1;
else right = mid - 1;
return false;
- mid 조정하고 최종적으로 false를 반환해서 true일 때 count 하도록 함.
.
.
.
이제 이진탐색을 왜 사용하는지 알 것 같음.
빠르니까 그리고 불필요한 연산 안 해도 되니까.
항상 브루트포스 방식을 사용했는데 이제는 이진 탐색을 사용해서 시간 복잡도를 줄일 수 있는 코드를 더 만들어봐야겠다.
'코테 - 자바' 카테고리의 다른 글
| 백준_11659 구간 합 구하기 (0) | 2026.03.05 |
|---|---|
| 코테 도전기1 (1) | 2025.12.16 |
| 정렬 - 코딩테스트 JAVA (0) | 2025.04.28 |
| 99클럽 코테 스터디 19일차 TIL + 이분탐색 (2) | 2025.04.24 |
| 99클럽 코테 스터디 18일차 TIL + 정렬(2) (2) | 2025.04.17 |