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

2025-2-13-4.5 二分法(基础题)

文章目录

  • 4.5 二分法(基础题)
    • **34. 在排序数组中查找元素的第一个和最后一个位置**
    • **2529. 正整数和负整数的最大计数**
    • **2300. 咒语和药水的成功对数**
    • **2563. 统计公平数对的数目**
    • **275. H值数 II**(至少问题)
    • **875. 爱吃香蕉的珂珂**(最小问题)
    • **2187. 完成旅途的最少时间**(最少,值得多做几遍,好好体会体会!)
    • **2861. 最大合金数**(典型应用题)
    • **2439. 最小化数组中的最大值**
    • **2517. 礼盒的最大甜蜜度**

4.5 二分法(基础题)

作者:灵茶山艾府

链接:https://leetcode.cn/problems/maximum-number-of-vowels-in-a-substring-of-given-length/solutions/

34. 在排序数组中查找元素的第一个和最后一个位置

题目:34. 在排序数组中查找元素的第一个和最后一个位置

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

举例

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]

提示:

  • 0 <= nums.length <= 10^5
  • -10^9 <= nums[i] <= 10^9
  • nums 是一个非递减数组
  • -10^9 <= target <= 10^9

代码:

def lower_bound(nums: List[int], target: int) -> int:left, right = 0, len(nums)-1while left <= right: # [left,right]mid = (left+right) // 2if nums[mid] < target:left = mid + 1 # [mid+1,right]else:right = mid - 1 # [left,mid-1]return leftclass Solution:def searchRange(self, nums: List[int], target: int) -> List[int]:"""时间复杂度:O(log n),n为nums的长度空间复杂度:O(1)"""start = lower_bound(nums,target)if start == len(nums) or nums[start] != target:return [-1,-1]end = lower_bound(nums,target+1) - 1return [start,end]

2529. 正整数和负整数的最大计数

题目:2529. 正整数和负整数的最大计数

给你一个按 非递减顺序 排列的数组 nums ,返回正整数数目和负整数数目中的最大值。

  • 换句话讲,如果 nums 中正整数的数目是 pos ,而负整数的数目是 neg ,返回 posneg二者中的最大值。

注意:0 既不是正整数也不是负整数。

举例

示例 1:

输入:nums = [-2,-1,-1,1,2,3]
输出:3
解释:共有 3 个正整数和 3 个负整数。计数得到的最大值是 3 。

示例 2:

输入:nums = [-3,-2,-1,0,0,1,2]
输出:3
解释:共有 2 个正整数和 3 个负整数。计数得到的最大值是 3 。

示例 3:

输入:nums = [5,20,66,1314]
输出:4
解释:共有 4 个正整数和 0 个负整数。计数得到的最大值是 4 。

提示:

  • 1 <= nums.length <= 2000
  • -2000 <= nums[i] <= 2000
  • nums非递减顺序 排列。

代码:

def lower_bound(nums: List[int], target: int) -> int:left, right = 0, len(nums)-1while left <= right:   #[left,right]mid = (left + right) // 2if nums[mid] < target:left = mid + 1 #[mid+1,right]else:right = mid - 1 #[left,mid-1]return left class Solution:def maximumCount(self, nums: List[int]) -> int:# This problem can convert to find the position of the zero"""时间复杂度:O(log n),n为nums的长度空间复杂度:O(1)"""neg = lower_bound(nums,0) pos = len(nums)-lower_bound(nums,1)return max(neg,pos)

2300. 咒语和药水的成功对数

题目: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 <= 10^5
  • 1 <= spells[i], potions[i] <= 10^5
  • 1 <= success <= 10^10

代码:

def lower_bound(nums: List[int], target: int) -> int:left, right = 0, len(nums)-1while left <= right: # [left,right]mid = (left + right)//2if nums[mid] < target:left = mid + 1 # [mid+1,right]else:right = mid - 1 # [left,mid-1]return leftclass Solution:def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]:'''python3的数据管理有点神,会根据实际情况提升数据精度时间复杂度:O(mlog n),m和n分别为spells与potions的长度空间复杂度:O(1)'''potions.sort()ans = []n = len(potions)for s in spells:ans.append(n - lower_bound(potions,success/s))return ans

2563. 统计公平数对的数目

题目:2563. 统计公平数对的数目

给你一个下标从 0 开始、长度为 n 的整数数组 nums ,和两个整数 lowerupper ,返回 公平数对的数目

如果 (i, j) 数对满足以下情况,则认为它是一个 公平数对

  • 0 <= i < j < n,且
  • lower <= nums[i] + nums[j] <= upper

举例

示例 1:

输入:nums = [0,1,7,4,4,5], lower = 3, upper = 6
输出:6
解释:共计 6 个公平数对:(0,3)、(0,4)、(0,5)、(1,3)、(1,4) 和 (1,5) 。

示例 2:

输入:nums = [1,7,9,2,5], lower = 11, upper = 11
输出:1
解释:只有单个公平数对:(2,3) 。

提示:

  • 1 <= nums.length <= 10^5
  • nums.length == n
  • -10^9 <= nums[i] <= 10^9
  • -10^9 <= lower <= upper <= 10^9

代码:

class Solution:def countFairPairs(self, nums: List[int], lower: int, upper: int) -> int:"""# 整出来这个公式就好了nums[i] and nums[j]lower - nums[j] <= nums[i] <= upper - nums[j]且 0 <= i < jdifference between bisect.bisect_left() and bisect_right()(1) 列表中没有查询元素x时,两者返回相同的值,即插入的位置;(2) 只有1个元素x时,left 返回该值所在位置,right 对应位置+1(3) 多个元素x时,left 返回元素x最左面的元素位置 right 最右端元素x的位置+1时间复杂度:O(nlogn),其中 n 为 nums 的长度。空间复杂度:O(1)。"""nums.sort()ans = 0for j, x  in enumerate(nums):# 查找的元素右边r = bisect_right(nums, upper - x, 0, j) l = bisect_left(nums, lower - x, 0, j) ans += r - lreturn ans 

275. H值数 II(至少问题)

题目:275. H 指数 II

给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数,citations 已经按照 升序排列 。计算并返回该研究者的 h 指数。

h 指数的定义:h 代表“高引用次数”(high citations),一名科研人员的 h 指数是指他(她)的 (n 篇论文中)至少h 篇论文分别被引用了至少 h 次。

请你设计并实现对数时间复杂度的算法解决此问题。

举例

示例 1:

输入:citations = [0,1,3,5,6]
输出:3
解释:给定数组表示研究者总共有 5 篇论文,每篇论文相应的被引用了 0, 1, 3, 5, 6 次。由于研究者有3篇论文每篇 至少 被引用了 3 次,其余两篇论文每篇被引用 不多于 3 次,所以她的 h 指数是 3 。

示例 2:

输入:citations = [1,2,100]
输出:2

提示:

  • n == citations.length
  • 1 <= n <= 10^5
  • 0 <= citations[i] <= 1000
  • citations升序排列

代码:

class Solution:def hIndex(self, citations: List[int]) -> int:"""时间复杂度:O(log n),n为citations的长度空间复杂度:O(1)"""n = len(citations)L,R = 0,n-1while L<=R:mid = (L+R)//2# 至少有n-mid篇的引用数大于citation[mid]if n-mid > citations[mid]:L = mid+1else:R = mid-1return n-L

875. 爱吃香蕉的珂珂(最小问题)

题目:875. 爱吃香蕉的珂珂

珂珂喜欢吃香蕉。这里有 n 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 h 小时后回来。

珂珂可以决定她吃香蕉的速度 k (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k 根。如果这堆香蕉少于 k 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。

珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。

返回她可以在 h 小时内吃掉所有香蕉的最小速度 kk 为整数)。

举例

示例 1:

输入:piles = [3,6,7,11], h = 8
输出:4

示例 2:

输入:piles = [30,11,23,4,20], h = 5
输出:30

示例 3:

输入:piles = [30,11,23,4,20], h = 6
输出:23

提示:

  • 1 <= piles.length <= 10^4
  • piles.length <= h <= 10^9
  • 1 <= piles[i] <= 10^9

代码:

class Solution:def minEatingSpeed(self, piles: List[int], h: int) -> int:"""时间复杂度:O(nlog U),n为piles的长度,U=max(piles)空间复杂度:O(1)"""left, right = 0, max(piles)n = len(piles)if h == n: return rightwhile left+1 < right:mid = (left+right)//2tmp = sum([math.ceil(i/mid) for i in piles])if tmp > h:left = midelse:right = midreturn right

2187. 完成旅途的最少时间(最少,值得多做几遍,好好体会体会!)

题目:2187. 完成旅途的最少时间

给你一个数组 time ,其中 time[i] 表示第 i 辆公交车完成 一趟****旅途 所需要花费的时间。

每辆公交车可以 连续 完成多趟旅途,也就是说,一辆公交车当前旅途完成后,可以 立马开始 下一趟旅途。每辆公交车 独立 运行,也就是说可以同时有多辆公交车在运行且互不影响。

给你一个整数 totalTrips ,表示所有公交车 总共 需要完成的旅途数目。请你返回完成 至少 totalTrips 趟旅途需要花费的 最少 时间。

举例

示例 1:

输入:time = [1,2,3], totalTrips = 5
输出:3
解释:
- 时刻 t = 1 ,每辆公交车完成的旅途数分别为 [1,0,0] 。已完成的总旅途数为 1 + 0 + 0 = 1 。
- 时刻 t = 2 ,每辆公交车完成的旅途数分别为 [2,1,0] 。已完成的总旅途数为 2 + 1 + 0 = 3 。
- 时刻 t = 3 ,每辆公交车完成的旅途数分别为 [3,1,1] 。已完成的总旅途数为 3 + 1 + 1 = 5 。
所以总共完成至少 5 趟旅途的最少时间为 3 。

示例 2:

输入:time = [2], totalTrips = 1
输出:2
解释:
只有一辆公交车,它将在时刻 t = 2 完成第一趟旅途。
所以完成 1 趟旅途的最少时间为 2 。

提示:

  • 1 <= time.length <= 10^5
  • 1 <= time[i], totalTrips <= 10^7

代码:

class Solution:def minimumTime(self, time: List[int], totalTrips: int) -> int:"""时间复杂度:O(nlog U),n为time的长度,U为二分上下界之差空间复杂度:O(1)"""min_t = min(time)avg = ceil(totalTrips/len(time))left = min_t * avg - 1 # 循环不变量1 sum >= totalTrips 恒为 False# 循环不变量2 sum >= totalTrips 恒为 Trueright = min(max(time)*avg, min_t*totalTrips) # 开区间 (left,right) 不为空while left + 1 < right:mid = (left + right) // 2if sum(mid//t for t in time) >= totalTrips:right = midelse:left = mid# sum(left) < totalTrips 且 sum(right) >= totalTrips return right

2861. 最大合金数(典型应用题)

题目:2861. 最大合金数

假设你是一家合金制造公司的老板,你的公司使用多种金属来制造合金。现在共有 n 种不同类型的金属可以使用,并且你可以使用 k 台机器来制造合金。每台机器都需要特定数量的每种金属来创建合金。

对于第 i 台机器而言,创建合金需要 composition[i][j]j 类型金属。最初,你拥有 stock[i]i 类型金属,而每购入一份 i 类型金属需要花费 cost[i] 的金钱。

给你整数 nkbudget,下标从 1 开始的二维数组 composition,两个下标从 1 开始的数组 stockcost,请你在预算不超过 budget 金钱的前提下,最大化 公司制造合金的数量。

所有合金都需要由同一台机器制造。

返回公司可以制造的最大合金数。

举例

示例 1:

输入:n = 3, k = 2, budget = 15, composition = [[1,1,1],[1,1,10]], stock = [0,0,0], cost = [1,2,3]
输出:2
解释:最优的方法是使用第 1 台机器来制造合金。
要想制造 2 份合金,我们需要购买:
- 2 份第 1 类金属。
- 2 份第 2 类金属。
- 2 份第 3 类金属。
总共需要 2 * 1 + 2 * 2 + 2 * 3 = 12 的金钱,小于等于预算 15 。
注意,我们最开始时候没有任何一类金属,所以必须买齐所有需要的金属。
可以证明在示例条件下最多可以制造 2 份合金。

示例 2:

输入:n = 3, k = 2, budget = 15, composition = [[1,1,1],[1,1,10]], stock = [0,0,100], cost = [1,2,3]
输出:5
解释:最优的方法是使用第 2 台机器来制造合金。 
要想制造 5 份合金,我们需要购买: 
- 5 份第 1 类金属。
- 5 份第 2 类金属。 
- 0 份第 3 类金属。 
总共需要 5 * 1 + 5 * 2 + 0 * 3 = 15 的金钱,小于等于预算 15 。 
可以证明在示例条件下最多可以制造 5 份合金。

示例 3:

输入:n = 2, k = 3, budget = 10, composition = [[2,1],[1,2],[1,1]], stock = [1,1], cost = [5,5]
输出:2
解释:最优的方法是使用第 3 台机器来制造合金。
要想制造 2 份合金,我们需要购买:
- 1 份第 1 类金属。
- 1 份第 2 类金属。
总共需要 1 * 5 + 1 * 5 = 10 的金钱,小于等于预算 10 。
可以证明在示例条件下最多可以制造 2 份合金。

提示:

  • 1 <= n, k <= 100
  • 0 <= budget <= 10^8
  • composition.length == k
  • composition[i].length == n
  • 1 <= composition[i][j] <= 100
  • stock.length == cost.length == n
  • 0 <= stock[i] <= 10^8
  • 1 <= cost[i] <= 100

代码:

class Solution:def maxNumberOfAlloys(self, n: int, k: int, budget: int, composition: List[List[int]], stock: List[int], cost: List[int]) -> int:"""跟做应用题似的,真复杂的时间复杂度:O(knlogU),其中 U=min(stock)+budget。空间复杂度:O(1)。"""ans = 0mx = min(stock) + budgetfor comp in composition:def check(num: int) -> bool:money = 0for s, base, c in zip(stock,comp,cost):if s < base * num:money += (base * num - s) * cif money > budget:return Falsereturn Trueleft, right =  ans, mx+1while left + 1 < right:mid = (left + right) // 2if check(mid):left = midelse:right = midans = leftreturn ans

2439. 最小化数组中的最大值

题目:2439. 最小化数组中的最大值

给你一个下标从 0 开始的数组 nums ,它含有 n 个非负整数。

每一步操作中,你需要:

  • 选择一个满足 1 <= i < n 的整数 i ,且 nums[i] > 0
  • nums[i] 减 1 。
  • nums[i - 1] 加 1 。

你可以对数组执行 任意 次上述操作,请你返回可以得到的 nums 数组中 最大值 最小 为多少。

举例

示例 1:

输入:nums = [3,7,1,6]
输出:5
解释:
一串最优操作是:
1. 选择 i = 1 ,nums 变为 [4,6,1,6] 。
2. 选择 i = 3 ,nums 变为 [4,6,2,5] 。
3. 选择 i = 1 ,nums 变为 [5,5,2,5] 。
nums 中最大值为 5 。无法得到比 5 更小的最大值。
所以我们返回 5 。

示例 2:

输入:nums = [10,1]
输出:10
解释:
最优解是不改动 nums ,10 是最大值,所以返回 10 。

提示:

  • n == nums.length
  • 2 <= n <= 10^5
  • 0 <= nums[i] <= 10^9

代码:

class Solution:def minimizeArrayValue(self, nums: List[int]) -> int:"""时间复杂度:O(nlogU),其中 n 为 nums 的长度,U=max(nums)。空间复杂度:O(1),仅用到若干变量。"""def check(limit: int) -> bool:extra = 0for i in range(len(nums)-1,0,-1):extra = max(nums[i]+extra-limit,0)return nums[0] + extra <= limitreturn bisect_left(range(max(nums)),True,lo=min(nums),key=check)

2517. 礼盒的最大甜蜜度

题目:2517. 礼盒的最大甜蜜度

给你一个正整数数组 price ,其中 price[i] 表示第 i 类糖果的价格,另给你一个正整数 k

商店组合 k不同 糖果打包成礼盒出售。礼盒的 甜蜜度 是礼盒中任意两种糖果 价格 绝对差的最小值。

返回礼盒的 最大 甜蜜度*。*

举例

示例 1:

输入:price = [13,5,1,8,21,2], k = 3
输出:8
解释:选出价格分别为 [13,5,21] 的三类糖果。
礼盒的甜蜜度为 min(|13 - 5|, |13 - 21|, |5 - 21|) = min(8, 8, 16) = 8 。
可以证明能够取得的最大甜蜜度就是 8 。

示例 2:

输入:price = [1,3,1], k = 2
输出:2
解释:选出价格分别为 [1,3] 的两类糖果。 
礼盒的甜蜜度为 min(|1 - 3|) = min(2) = 2 。
可以证明能够取得的最大甜蜜度就是 2 。

示例 3:

输入:price = [7,7,7,7], k = 2
输出:0
解释:从现有的糖果中任选两类糖果,甜蜜度都会是 0 。

提示:

  • 2 <= k <= price.length <= 10^5
  • 1 <= price[i] <= 10^9

代码:

class Solution:def maximumTastiness(self, price: List[int], k: int) -> int:"""时间复杂度:O(nlogn+nlogU),其中 n 为 price 的长度,U= (max(price)−min(price))/(k−1)空间复杂度:O(1)。"""def check(d: int) -> int:cnt = 1pre = price[0] # 先选甜度最小的for p in price:if p >= pre + d:cnt += 1pre = p  # 上一个选的甜度return cntprice.sort()left = 0right = (price[-1]-price[0]) // (k - 1) + 1while left + 1 < right:mid = (left + right) // 2if check(mid) >= k:left = midelse:right = midreturn left

http://www.mrgr.cn/news/90616.html

相关文章:

  • 算法与数据结构(存在重复元素)
  • cap2:1000分类的ResNet的TensorRT部署指南(python版)
  • java练习(19)
  • 细说STM32F407单片机RTC的基本原理及闹钟和周期唤醒功能的使用方法
  • 算法-计算字符的最短距离
  • pdf.js默认显示侧边栏和默认手形工具
  • 文字转语音(三)FreeTTS实现
  • macOS部署DeepSeek-r1
  • 使用HX搭建UNI-APP云开发项目(适合新手小白与想学云开发的宝子)
  • 【FastAPI 使用FastAPI和uvicorn来同时运行HTTP和HTTPS的Python应用程序】
  • DeepSeek AI 满血版功能集成到WPS或Microsoft Office中
  • cap1:TensorRT介绍及CUDA环境安装
  • 解决QPixmap报“QPixmap::grabWindow(): Unable to copy pixels from framebuffer“问题
  • 【云安全】云原生- K8S etcd 未授权访问
  • 20250212:sigmastar系列2-获取UUID进行授权
  • Radius协议详解
  • Qt的isVisible ()函数介绍和判断窗口是否在当前界面显示
  • Word 公式转 CSDN 插件 发布
  • deepseek本地部署
  • 【地理坐标Geo】——8
  • AI前端开发:蓬勃发展的机遇与挑战
  • 【Pandas】pandas Series drop
  • CZML 格式详解,javascript加载导出CZML文件示例
  • HR告诉你,机器视觉公司招聘真相!
  • AI前端开发:跨领域合作的新引擎
  • 【DuodooBMS】江苏新材料行业重资产数字化管理解决方案——从传感器到平台的全链路智能升级,赋能新材料智造新范式