题目链接及描述
2300. 咒语和药水的成功对数 - 力扣(LeetCode)

题目分析
这道题目作为一个典型的二分查找,题目中所述,找到每一个spells[i]在positions中对应的元素positions[i]使其乘积大于给定元素sucess,并统计每一个spell[i]所对应的positions中所查找元素的个数,并将其返回。
本题本质思想并不难:
long num = ((success % (long)spells[i]) == 0) ? (success / (long)spells[i]) : (success / (long)spells[i] + 1);
难点分析一:需要将计算出来的num设置为long类型,若设置为int,则强转为int会出现出现精度丢失,通过不了全部测试用例。
难点分析二:如何根据给定数组positions,查找第一个大于等于目标值target所对应的下标:
根据以上分析可以定义左边界L=0,右边界R = positions.length。并定义循环while(L < R)。
- public int getFirstNum(int[] potions, long target){
- int L = 0, R = potions.length;
- while(L < R){
- int midIdx = (L + R) / 2;
- long mid = (long)potions[midIdx];
- if(mid >= target){
- R = midIdx;
- }else{
- L = midIdx + 1;
- }
- }
- return R;
- }
关于上面的右边界的定义为什么不将R定义为R = positions.lenth - 1,如果这样定义,由于返回值为L == R,此时对于数组positions中不存在对应目标元素target的情况仍然返回下标len - 1,无法判断数组中存不存在第一个大于等于目标元素traget对应的元素。
引申扩展:如何找到数组positions中第一个小于等于目标元素target对应的下标?
- public int getFirstNum(int[] potions, long target){
- int L = -1, R = potions.length - 1;
- while(L < R){
- int midIdx = (L + R) / 2;
- long mid = (long)potions[midIdx];
- if(mid > target){
- R = midIdx - 1;
- }else if(mid <= target){
- L = midIdx;
- }
- }
- return R;
- }
代码编写
- class Solution {
- public int[] successfulPairs(int[] spells, int[] potions, long success) {
- Arrays.sort(potions);
- int n = spells.length;
- int[] ans = new int[n];
- for(int i = 0; i < n; i++){
- long num = ((success % (long)spells[i]) == 0) ? (success / (long)spells[i]) : (success / (long)spells[i] + 1);
- int res = getFirstNum(potions, num);
- if(res >= 0 && res < potions.length){
- ans[i] = potions.length - res;
- }
- }
- return ans;
- }
- public int getFirstNum(int[] potions, long target){
- int L = 0, R = potions.length;
- while(L < R){
- int midIdx = (L + R) / 2;
- long mid = (long)potions[midIdx];
- if(mid >= target){
- R = midIdx;
- }else{
- L = midIdx + 1;
- }
- }
- return R;
- }
- }