当前位置: 首页 > news >正文

咒语和药水的成功对数

问题描述

给你两个正整数数组 spellspotions,长度分别为 nm,其中 spells[i] 表示第 i 个咒语的能量强度,potions[j] 表示第 j 瓶药水的能量强度。同时给你一个整数 success。一个咒语和药水的能量强度相乘如果大于等于 success,则视为一对成功的组合。

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

示例:

  • 输入:spells = [5,1,3], potions = [1,2,3,4,5], success = 7,输出:[4,0,3]
    • 第0个咒语(5)与药水[2,3,4,5]组合成功(5×2=10≥7),共4对
    • 第1个咒语(1)与所有药水组合都不满足(1×5=5<7),共0对
    • 第2个咒语(3)与药水[3,4,5]组合成功(3×3=9≥7),共3对
  • 输入:spells = [3,1,2], potions = [8,5,8], success = 16,输出:[2,0,2]

约束条件:

  • n == spells.lengthm == potions.length
  • 1 <= n, m <= 10^5
  • 1 <= spells[i], potions[i] <= 10^5
  • 1 <= success <= 10^10

解题思路

核心分析

对于每个咒语 spells[i],需要找到满足 spells[i] * potions[j] >= success 的药水数量。直接遍历所有药水(时间复杂度 O(n*m))会因数据规模过大(105×105=10^10 操作)超时,因此需要更高效的方法。

最优解法:排序 + 二分查找

  1. 排序药水数组:对 potions 排序,为二分查找做准备(时间 O(m log m))。
  2. 二分查找每个咒语的临界值
    • 对于咒语 s,满足 s * p >= success 的药水 p 需满足 p >= ceil(success / s)(向上取整)。
    • 在排序后的 potions 中,用二分查找找到第一个大于等于临界值的位置,该位置右侧的所有元素均满足条件。
    • 成功对数 = 药水总数 - 临界位置索引(时间 O(n log m))。

关键公式

临界值计算:target = (success + s - 1) // s(用整数运算实现向上取整,避免浮点数精度问题)。

代码实现

C++ 实现

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;class Solution {
public:vector<int> successfulPairs(vector<int>& spells, vector<int>& potions, long long success) {int n = spells.size();int m = potions.size();vector<int> pairs(n);// 排序药水数组sort(potions.begin(), potions.end());for (int i = 0; i < n; ++i) {long long s = spells[i];// 计算临界药水值(向上取整)long long target = (success + s - 1) / s;// 找到第一个 >= target 的位置auto it = lower_bound(potions.begin(), potions.end(), target);// 成功对数 = 总数 - 位置索引pairs[i] = potions.end() - it;}return pairs;}
};int main() {Solution solution;vector<int> spells1 = {5,1,3};vector<int> potions1 = {1,2,3,4,5};vector<int> res1 = solution.successfulPairs(spells1, potions1, 7);for (int num : res1) cout << num << " ";  // 输出: 4 0 3 cout << endl;vector<int> spells2 = {3,1,2};vector<int> potions2 = {8,5,8};vector<int> res2 = solution.successfulPairs(spells2, potions2, 16);for (int num : res2) cout << num << " ";  // 输出: 2 0 2cout << endl;return 0;
}

Python 实现

import bisect
from typing import Listclass Solution:def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]:m = len(potions)pairs = []# 排序药水数组potions.sort()for s in spells:# 计算临界药水值(向上取整)target = (success + s - 1) // s# 找到第一个 >= target 的位置pos = bisect.bisect_left(potions, target)# 成功对数 = 总数 - 位置索引pairs.append(m - pos)return pairs# 测试
solution = Solution()
print(solution.successfulPairs([5,1,3], [1,2,3,4,5], 7))  # 输出: [4, 0, 3]
print(solution.successfulPairs([3,1,2], [8,5,8], 16))     # 输出: [2, 0, 2]

Java 实现

import java.util.Arrays;public class SuccessfulPairs {public int[] successfulPairs(int[] spells, int[] potions, long success) {int n = spells.length;int m = potions.length;int[] pairs = new int[n];// 排序药水数组Arrays.sort(potions);for (int i = 0; i < n; i++) {long s = spells[i];// 计算临界药水值(向上取整)long target = (success + s - 1) / s;// 找到第一个 >= target 的位置int pos = lowerBound(potions, target);// 成功对数 = 总数 - 位置索引pairs[i] = m - pos;}return pairs;}// 自定义二分查找,返回第一个 >= target 的位置private int lowerBound(int[] arr, long target) {int left = 0, right = arr.length;while (left < right) {int mid = left + (right - left) / 2;if (arr[mid] < target) {left = mid + 1;} else {right = mid;}}return left;}public static void main(String[] args) {SuccessfulPairs solution = new SuccessfulPairs();int[] spells1 = {5, 1, 3};int[] potions1 = {1, 2, 3, 4, 5};int[] res1 = solution.successfulPairs(spells1, potions1, 7);for (int num : res1) System.out.print(num + " ");  // 输出: 4 0 3 System.out.println();int[] spells2 = {3, 1, 2};int[] potions2 = {8, 5, 8};int[] res2 = solution.successfulPairs(spells2, potions2, 16);for (int num : res2) System.out.print(num + " ");  // 输出: 2 0 2System.out.println();}
}

复杂度分析

操作时间复杂度空间复杂度
排序药水数组O(m log m)O(log m)
处理所有咒语O(n log m)O(1)
整体O(m log m + n log m)O(n + log m)

总结

本题的最优解法通过排序+二分查找将时间复杂度从暴力法的 O(n*m) 优化至 O((n+m) log m),完美适配 10^5 级别的数据规模。核心思路是:

  1. 排序药水数组,为高效查询奠定基础;
  2. 对每个咒语计算临界药水值,利用二分查找快速定位符合条件的药水范围;
  3. 通过整数运算 (success + s - 1) // s 精准实现向上取整,避免浮点数精度问题。

这种方法兼顾了时间效率和实现简洁性,是处理此类“范围查询”问题的典型范式。

http://www.dtcms.com/a/459220.html

相关文章:

  • 天津网站建设优选企业如何用国外网站做头条
  • 网站建设公司的出路锦州网站推广
  • 网站建设推广书籍论坛企业推广
  • 好的免费网站建站平台响应式网站实例
  • 2025-10-08 Python 标准库 3——内置常量
  • 小企业网站维护什么东西网站制作南宁
  • 可以做猫头像的网站安装2个wordpress
  • 工业元宇宙:数字孪生开发框架设计精髓
  • 企业网站管理的含义及内容免费高清大图网站
  • 站长之家官网查询专门做超市dm网站
  • 网站做备案关于科技的名言
  • 北京门户网站制作公司做网站赚钱容易吗
  • 平台网站功能彩票网站制作
  • 网站服务器有哪些类型有哪些类型有哪些类型有哪些类型抚州建设公司网站
  • PerfTest 分布式集群测试实战,让压测回归简单
  • java oom排查
  • 咨询学校网站开发费用做外贸网站信息
  • wordpress发布文章提示失败厦门网站优化公司
  • 网站 系统设置如何做优化网站排名
  • 网站备案填了虚假座机能过吗上海制作公司
  • 毕业设计心理评测网站开发高密专业网站建设价格
  • 珠宝销售网站源码wordpress网站如何添加栏目
  • 深圳龙华网站开发手游代理平台哪个好
  • 江苏专业做网站的公司有哪些百度seo排名优化联系方式
  • 如何做网站搜索栏网站建设流程方案
  • 学校网站系统破解版中国企业网
  • 微信公众号自己微网站吗有哪些可以做兼职的翻译网站
  • 精品课程网站建设步骤培训网站开发需求说明书
  • 小型网站制作深圳wordpress前端新增头像上传
  • 优秀国外网站设计赏析网站怎样做全国地区推广