LeetCode每日一题,20251008
[咒语和药水的成功对数](https://leetcode.cn/problems/successful-pairs-of-spells-and-potions/description/?envType=daily-question&envId=2025-10-08)
题目介绍,给你两个数据a
,b
,对于每个a[i]
,找到b
中有多少个数满足a[i] * b[j] >= success
方法一
排序b数组,对于每个a[i],二分出有多少符合条件的b
import java.util.Arrays;public class SolutionBS {public int[] successfulPairs(int[] spells, int[] potions, long success) {int n = spells.length, m = potions.length;int[] res = new int[n];Arrays.sort(potions); // 升序for (int i = 0; i < n; i++) {long need = (success + spells[i] - 1L) / spells[i]; // ceil(success / spells[i])int pos = lowerBound(potions, need); // [0..m]res[i] = m - pos; // 不需要判断 pos<0}return res;}// 返回第一个 >= target 的下标;若都小于 target,则返回 mprivate int lowerBound(int[] a, long target) {int l = 0, r = a.length; // 区间不变量:[l, r)while (l < r) {int mid = l + ((r - l) >>> 1); // 等价于 (l + r) / 2,但避免溢出if ((long)a[mid] >= target) {r = mid;} else {l = mid + 1;}}return l; // l==r}
}
方法二
后缀和,数据量b数组的数字大小为1e5,统计每个数字出现的次数cnt,然后对于每次询问,可以直接找到有多少个数满足
比如 potions=[1,2,2,3,5,5,5],要计算 ≥2 的药水的个数,我们可以统计每个数出现了多少次,记在一个 cnt 数组中。在这个例子中,cnt=[0,1,2,1,0,3],比如 cnt[5]=3 表示 5 出现了 3 次。
class Solution {public int[] successfulPairs(int[] spells, int[] potions, long success) {int mx = 0;for (int y : potions) {mx = Math.max(mx, y);}int[] cnt = new int[mx + 1];for (int y : potions) {cnt[y]++; // 统计每种药水的出现次数}// 计算 cnt 的后缀和for (int i = mx - 1; i >= 0; i--) {cnt[i] += cnt[i + 1];}// 计算完毕后,cnt[i] 就是 potions 值 >= i 的药水个数for (int i = 0; i < spells.length; i++) {long low = (success - 1) / spells[i] + 1;spells[i] = low <= mx ? cnt[(int) low] : 0;}return spells;}
}