BinarySearch-징검 다리
문제 : 징검 다리 (LEVEL 4)
바위를 n 개 제거한 뒤 각 지점 사이 거리의 최솟값을 구한다.
그 최솟값 중에 가장 큰 값을 return
파라메트릭 서치
최적화 문제를 결정문제로 바꾸어 해결하는 기법
되냐/안되냐?를 범위를 좁혀가며 탐색함으로써 최적의 해를 구함
=> 조건 : 현재 이 높이로 자르면 떡 최소 조건 만족 ? –> 만족 여부(예, 아니오) 도출
=> 범위를 좁힐 때 ‘이진 탐색’
핵심 아이디어
: 지점간 최소 거리를 탐색의 범위로 해서 그 안의 최댓값을 찾음
ㅡㅡㅡㅡㅡㅡㅡㅡㅡ | ㅡㅡㅡㅡㅡㅡㅡㅡㅡ |
- 지점 간 최소 거리의 최소값 : 1
- 지점 간 최소 거리의 최댓값 : 25 (도착지점이 떨어진 위치)
=> 이분 탐색으로 최댓값을 설정하고, 바위를 없애가면서 그게 최댓값이 맞는지 확인 (바위를 이거저거 없애보면서
<-> 바위 사이 거리의 최솟값 중 최대값을 k로 설정했을 때, 없애야할 바위수?
(이게 문제에 주어진 조건 (n)과 같은지 확인)
ex) 첫번째 탐색
left : 1, right: 25, mid: 13
시작 ~ 2번 바위의 거리는 2이며, 13 보다 작다. 2번 바위 제거
시작 ~ 4번 바위의 거리는 4이며, 13 보다 작다. 4번 바위 제거
지점 간 최소거리를 13으로 가정하면, 총 6개의 바위가 제거 된다.
우리가 제거 해야할 바위는 2개이므로 최소 거리를 줄여서 재탐색 해야 한다.
구현 (코드)
import java.util.* ;
class Solution {
public int solution(int distance, int[] rocks, int n) {
int answer = 0 ;
Arrays.sort(rocks) ; // 돌이 놓여진 위치 정렬
// 이분 탐색 : 바위를 n개 제거한 뒤 각 지점 사이 거리의 최솟값
// ㄴ 그 최솟값이 될 수 있는 값 중 최댓값이 최종적으로 구하는 값
int left = 1 ;
int right = distance ;
while(left <= right){
int mid = (left+right)/2 ;
if(getRemovedRockCnt(rocks ,mid, distance)<=n){ // 해당 mid가 답이 되는 돌 제거 수가 조건보다 적으면
left = mid + 1 ; // 최소 거리를 더 크게 잡아서 돌을 더 제거시켜주고
answer = mid ; // 다음 반복에서 해가 안나올 수 있기 때문에 허용 가능 범위일 때 일단 answer에 mid값을 저장해준다 **
}else{ // 해당 mid가 답이 되기 위해 돌이 더 많이 제거 되면
right = mid -1; // 돌간 최소 거리를 작게 잡아서 돌을 덜 제거해야한다
}
}
return answer ;
}
public int getRemovedRockCnt(int[] rocks, int mid, int distance){
// mid 가 바위 지점 간 최소거리가 되기 위해 제거해야할 바위의 수를 return한다
// mid가 바위 지점간 최소 거리가 되려면 mid보다 작은 숫자의 거리가 나오면 해당 돌을 제거해야한다
// 실제로 돌을 제거하지 않고 제거해야'할' 돌의 갯수를 세는게 포인트
int before = 0 ; // 출발지
int end = distance ;
int removeCnt = 0 ;
for(int i = 0 ; i < rocks.length ; i++){ // 돌 하나하나 검사하면서
if(rocks[i] - before < mid){ // 이전 돌과의 거리가 mid보다 작으면
removeCnt++ ; // mid가 최솟값이 아닌게 되므로 돌제거 (제거할 돌 수 ++)
continue ;
}
before = rocks[i] ; // '이전 돌'을 검사한 돌로 갱신
}
if(end - before < mid) removeCnt++ ; // 마지막 돌과 도착지 사이의 거리(mid보다 짧으면 마지막 돌 제거)
return removeCnt ;
}
}
댓글남기기