day118—二分查找—咒语和药水的成功对数(LeetCode-2300)

题目描述

给你两个正整数数组 spellspotions ,长度分别为 nm ,其中 spells[i] 表示第 i 个咒语的能量强度,potions[j] 表示第 j 瓶药水的能量强度。

同时给你一个整数 success 。一个咒语和药水的能量强度 相乘 如果 大于等于 success ,那么它们视为一对 成功 的组合。

请你返回一个长度为 n 的整数数组pairs,其中pairs[i] 是能跟第 i 个咒语成功组合的 药水 数目。

示例 1:

复制代码
输入:spells = [5,1,3], potions = [1,2,3,4,5], success = 7
输出:[4,0,3]
解释:
- 第 0 个咒语:5 * [1,2,3,4,5] = [5,10,15,20,25] 。总共 4 个成功组合。
- 第 1 个咒语:1 * [1,2,3,4,5] = [1,2,3,4,5] 。总共 0 个成功组合。
- 第 2 个咒语:3 * [1,2,3,4,5] = [3,6,9,12,15] 。总共 3 个成功组合。
所以返回 [4,0,3] 。

示例 2:

复制代码
输入:spells = [3,1,2], potions = [8,5,8], success = 16
输出:[2,0,2]
解释:
- 第 0 个咒语:3 * [8,5,8] = [24,15,24] 。总共 2 个成功组合。
- 第 1 个咒语:1 * [8,5,8] = [8,5,8] 。总共 0 个成功组合。
- 第 2 个咒语:2 * [8,5,8] = [16,10,16] 。总共 2 个成功组合。
所以返回 [2,0,2] 。

提示:

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

解决方案:

算法目标

对于每个法术,统计有多少药水能够与之组成成功对(满足:法术强度 × 药水强度 ≥ 目标值)

核心思路

  1. 预处理药水:先排序药水数组,便于二分查找

  2. 对每个法术:找到能使其成功的最小药水强度

  3. 二分统计:通过二分查找统计满足条件的药水数量

关键步骤

1. 排序药水

sort(potions.begin(), potions.end());

  • 排序后可以使用二分查找高效定位

  • 时间复杂度:O(m log m),m为药水数量

2. 计算每个法术的成功对数

spells[i] = p_len - lower_bound(potions, 1.0*success/spells[i]);

  • 1.0*success/spells[i]:计算所需的最小药水强度

    • 使用浮点数避免整数除法向下取整

    • 需要满足:spell × potion ≥ success

    • 即:potion ≥ success / spell

  • lower_bound(potions, min_value):返回第一个 ≥ 最小药水强度的位置

  • p_len - 位置:从该位置开始的所有药水都满足条件

算法流程示例

输入:

spells = [5, 1, 3] potions = [1, 2, 3, 4, 5] success = 7

  1. 排序后 potions = [1, 2, 3, 4, 5]

  2. 计算:

    • 法术5:7/5.0=1.4→ 第一个≥1.4的药水是2(索引1)→ 成功对数=5-1=4

    • 法术1:7/1.0=7.0→ 第一个≥7.0的药水不存在(索引5)→ 成功对数=5-5=0

    • 法术3:7/3.0≈2.333→ 第一个≥2.333的药水是3(索引2)→ 成功对数=5-2=3

  3. 结果:[4, 0, 3]

时间复杂度

  • 排序:O(m log m),m为药水数量

  • 计算每个法术:n次二分查找,每次O(log m)

  • 总时间:O(m log m + n log m)

潜在问题

  1. 除零错误 :当spells[i]=0时,1.0*success/0会崩溃

  2. 浮点数精度:浮点数比较可能有精度误差

  3. 溢出风险successlong long,但计算时转为double

优点

  • 代码简洁

  • 充分利用二分查找提高效率

  • 思路清晰直观

可改进点

  1. 添加对spell=0的特殊处理

  2. 考虑使用整数向上取整避免浮点数精度问题

  3. 可以使用乘法比较替代除法

总体来说,这是一个利用排序+二分查找高效解决组合计数问题的典型算法。

函数源码:

cpp 复制代码
class Solution {
public:
    int lower_bound(vector<int>& nums, double target) {
        int len =nums.size();
        int left=-1;
        int right=len;
        int mid;

        while(left+1<right){
            mid=(left+right)/2;
            if((double)nums[mid]<target){
                left=mid;
            }else{
                right=mid;
            }
        }
        return right;

    }

    vector<int> successfulPairs(vector<int>& spells, vector<int>& potions, long long success) {
        sort(potions.begin(),potions.end());
        int len=spells.size();
        int p_len=potions.size();
        for(int i=0;i<len;i++){
            spells[i]= p_len - lower_bound(potions,1.0*success/spells[i]);
        }
        return spells;
    }
};
相关推荐
啊森要自信21 小时前
CANN ops-cv:AI 硬件端视觉算法推理训练的算子性能调优与实战应用详解
人工智能·算法·cann
仟濹1 天前
算法打卡day2 (2026-02-07 周五) | 算法: DFS | 3_卡码网99_计数孤岛_DFS
算法·深度优先
驭渊的小故事1 天前
简单模板笔记
数据结构·笔记·算法
YuTaoShao1 天前
【LeetCode 每日一题】1653. 使字符串平衡的最少删除次数——(解法一)前后缀分解
算法·leetcode·职场和发展
VT.馒头1 天前
【力扣】2727. 判断对象是否为空
javascript·数据结构·算法·leetcode·职场和发展
goodluckyaa1 天前
LCR 006. 两数之和 II - 输入有序数组
算法
孤狼warrior1 天前
YOLO目标检测 一千字解析yolo最初的摸样 模型下载,数据集构建及模型训练代码
人工智能·python·深度学习·算法·yolo·目标检测·目标跟踪
Σίσυφος19001 天前
PCL法向量估计 之 RANSAC 平面估计法向量
算法·机器学习·平面
xhbaitxl1 天前
算法学习day39-动态规划
学习·算法·动态规划
I_LPL1 天前
day23 代码随想录算法训练营 回溯专题2
算法·hot100·回溯算法·求职面试