[PCCP 기출문제] 2번 / 퍼즐 게임 챌린지
문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/340212
접근 방식
난이도에서 최솟값과 최댓값을 구해서
최솟값부터 하나씩 증가해가면서, 게임이 가능하다면 최솟값을 갱신하면 된다.
잘못된 접근
import java.util.*;
class Solution {
public int solution(int[] diffs, int[] times, long limit) {
int answer = Integer.MAX_VALUE;
int min = Arrays.stream(diffs).min().getAsInt(); // 최솟값
int max = Arrays.stream(diffs).max().getAsInt(); // 최댓값
for(int i=min; i<=max; i++){
if(game(diffs, times, limit, i)){
answer = Math.min(answer, i);
}
}
return answer;
}
boolean game(int[] diffs, int[] times, long limit, int num){
long tmp = limit - times[0];
for(int i=1; i<diffs.length; i++){
if(diffs[i] <= num){
tmp -= times[i];
}else{
tmp -= (long)(times[i-1]+times[i]) * (diffs[i]-num) + times[i];
}
if(tmp < 0L) return false;
}
return true;
}
}
최대 연산 횟수가 30만 * 10만
이기에
이분탐색을 통해, 최솟값과 최댓값을 동시에 변경하여 탐색 범위를 최소화해야 한다.
잘 된 접근
while(left<=right){
int mid = (left + right)/2;
if(game(diffs, times, limit, mid)){
answer = Math.min(answer, mid);
right = mid-1;
}else{
left = mid+1;
}
}
left는 최솟값, right는 최댓값으로 설정하고 중단값을 정한다.
그리고 중단값으로 가능하다면, right을 줄이고, 불가능하다면 left를 올려 값을 구해나간다.
결과
소스 코드
import java.util.*;
class Solution {
public int solution(int[] diffs, int[] times, long limit) {
int answer = Integer.MAX_VALUE;
int min = Arrays.stream(diffs).min().getAsInt(); // 최솟값
int max = Arrays.stream(diffs).max().getAsInt(); // 최댓값
int left=min, right=max;
while(left<=right){
int mid = (left + right)/2;
if(game(diffs, times, limit, mid)){
answer = Math.min(answer, mid);
right = mid-1;
}else{
left = mid+1;
}
}
return answer;
}
boolean game(int[] diffs, int[] times, long limit, int num){
long tmp = limit - times[0];
for(int i=1; i<diffs.length; i++){
if(diffs[i] <= num){
tmp -= times[i];
}else{
tmp -= (long)(times[i-1]+times[i]) * (diffs[i]-num) + times[i];
}
if(tmp < 0L) return false;
}
return true;
}
}