항해99 코테 스터디 22일차 문제인 리트코드 786번 문제는 정수 배열에서 두 수를 뽑아 만드는 분수들 중 k번째를 찾는 문제다. 난이도는 Medium이며 완전탐색 또는 이분탐색을 통해 해결할 수 있다.
오늘의 문제 - K-th Smallest Prime Fraction 문제 정보
문제 키워드
- BS
난이도
- Medium
문제 요약
- 1과 소수로만 이루어진 오름차순 정수 배열 arr가 주어진다. (배열 내의 정수는 중복되지 않는다)
- 0 ≤ i < j < arr.length인 모든 (i, j)에 대해 분수 arr[i]/arr[j]를 계산했을 때, k번째로 작은 분수를 구하여 정답으로 [arr[i], arr[j]]를 반환하여라.
문제 풀이 과정
- N≤10000이라서 O(N^2)으로도 풀리지만, 키워드가 이진탐색인 만큼 더 작은 시간복잡도로 풀어보려 하였다. (O(NlogN)정도)
- 이진 탐색을 사용하기 위해서, 어떤 것을 범위로 잡고 어떤 조건을 이용해 범위를 줄여나갈 것인지를 결정해야 했다.
- 분수를 계산하는 문제이기 때문에 0~1을 시작 범위로 하고 반씩 줄여나가면 어떨까 생각은 했는데, 중간값보다 작은 분수의 개수를 구하는 것이 O(N^2)로 구하는 방법 말고는 떠오르지가 않았다.
- GPT와 많은 씨름을 한 끝에… 정렬된 배열에서 두 수를 뽑아 분수를 만들었을 때, 특정 값보다 작은 분수의 개수를 구하는 O(N)짜리 방법을 알게 되었다.
- 따라서 이진탐색으로 low와 high의 범위를 줄여갈 때 사용되는 조건으로, mid값보다 작거나 같은 분수의 개수가 k개 미만/초과/같은 경우에 따라 다음 루프로 넘어가도록 하였다.
- 여기서 k개와 같아진다면, mid보다 작거나 같은 가장 큰 분수를 반환한다.
코드
class Solution { public int[] kthSmallestPrimeFraction(int[] arr, int k) { return bs(arr, 0, 1, k); } // low~high 범위 내에서 k번째 분수를 구하는 메서드 private int[] bs(int[] arr, double low, double high, int k) { while(low < high) { double mid = (low+high)/2; // 중간값보다 작거나 같은 분수의 개수 및 그 중 가장 큰 분수를 구함 int[] smallerF = getSmallerFraction(arr, mid); int cnt = smallerF[0]; if (cnt == k) { return new int[]{smallerF[1], smallerF[2]}; } else if (cnt < k) { low = mid; } else { high = mid; } } return null; } private int[] getSmallerFraction(int[] arr, double num) { int cnt = 0; int maxT = 0, maxB = 1; int j = 0; for(int i=0; i<arr.length-1; i++) { int hereT = arr[i]; // 분자(arr[i])를 고정하고 분모(arr[j])를 증가시키면서 // num보다 작거나 같은 최대 분모를 구함 while (j < arr.length && hereT >= num * arr[j]) { j++; } // 현재 분자로 num보다 작은 경우가 없으면 종료 if (j==arr.length) { break; } // 현재 분자로 num보다 작은 분모의 개수만큼 cnt 증가 cnt += (arr.length-j); int hereB = arr[j]; // 최대 분수 갱신 if (j < arr.length && (hereT*maxB > maxT*hereB)) { maxT = hereT; maxB = hereB; } } return new int[]{cnt, maxT, maxB}; } }
- 시간복잡도: O(NlogN)
- 공간복잡도: O(1)
오늘의 학습 회고
- 이분탐색을 떠올리고, 구성하는 흐름을 좀 더 연습해야겠다.
728x90
'알고리즘 > 항해99 스터디' 카테고리의 다른 글
99클럽 코테 스터디 25일차 TIL - 그래프 (LeetCode 1971번) (0) | 2024.06.13 |
---|---|
99클럽 코테 스터디 24일차 TIL - 그래프 (프로그래머스 '방의 개수') (0) | 2024.06.12 |
99클럽 코테 스터디 22일차 TIL - Binary Search (프로그래머스 '징검다리') (0) | 2024.06.10 |
99클럽 코테 스터디 21일차 TIL - DP (프로그래머스 '도둑질') (0) | 2024.06.10 |
99클럽 코테 스터디 20일차 TIL - DP (프로그래머스 '사칙연산') (0) | 2024.06.08 |
댓글