PS/Medium

2300. Successful Pairs of Spells and Potions (이진 탐색)

우봉수 2023. 4. 10. 15:57

제약:

  • n == spells.length
  • m == potions.length
  • 1 <= n, m <= 105
  • 1 <= spells[i], potions[i] <= 105
  • 1 <= success <= 1010

<아이디어>

long 타입의 success를 비교하는 방법은 (long)spell*potion >= success 타입 캐스팅을 통해 해결이 가능하다.

문제점은 단순 이중 for문을 통해 해결 하려할 경우 제한 시간 초과가 나오기 때문에

선형 탐색보다 더 빠른 이분 탐색을 사용 할 필요가 있었다. 

여기서 우리가 배열에서 찾아야 할 건 주어진 비교식에 처음으로 성립하는 값이다.

 

<정답 코드>

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

class Solution {
    // 시간 복잡도 O(nlog m) 공간 복잡도 O(1)
    public int[] successfulPairs(int[] spells, int[] potions, long success) {
        List<Integer> ans = new ArrayList<>();
        int m = potions.length;
        Arrays.sort(potions);
        for (int spell : spells) {
            int left = 0;
            int right = m-1;
            // 이분 탐색 변형
            while(left<=right){
                // System.out.println(left+", "+right);
                int mid = left+(right-left)/2;
                long tmp = (long)spell*potions[mid];
                // 종료 조건을 넣지 않는 이유는 배열에서 주어진 비교식에 처음으로 성립하는 값을 찾기 위해서다.
                // 찾는 값이 mid의 해당하는 값보다 작거나 같다면 탐색 범위의 오른쪽의 범위를 좁힌다.
                if(tmp>=success)
                    right = mid-1;
                // 찾는 값이 mid의 해당하는 값보다 크다면 탐색 범위의 오른쪽의 범위를 좁힌다.
                else
                    left = mid+1;
            }
            ans.add(m-left);
        }
        // 리스트 보다는 일반 배열을 사용하는걸 권장한다.
        return ans.stream().mapToInt(i->i).toArray();
    }
}