二分查找例题

本篇基于b站灵茶山艾府

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]

class Solution:
    def lower_bound(self, nums, target):  # 左闭右闭区间
        left = 0
        right = len(nums) - 1
        # 区间内表示未分类
        while left <= right:  # 区间不为空
            mid = (left + right) // 2
            if nums[mid] < target:
                left = mid + 1  # [mid+1,right]
            else:
                right = mid - 1  # [left,mid-1]

        # left-1都是表示小于target的
        # right+1都是表示大于等于target的
        return left  # 返回的是大于等于target的值

    def lower_bound2(self, nums, target):  # 左闭右开区间
        left = 0
        right = len(nums)
        # 区间内表示未分类
        while left != right:  # 区间不为空
            mid = (left + right) // 2
            if nums[mid] < target:
                left = mid + 1  # [mid+1,right]
            else:
                right = mid  # [left,mid)

        # left-1都是表示小于target的
        # right都是表示大于等于target的
        return left  # right

    def lower_bound3(self, nums, target):  # 左开右开区间
        left = -1
        right = len(nums)
        # 区间内表示未分类
        while left + 1 != right:  # 区间不为空
            mid = (left + right) // 2
            if nums[mid] < target:
                left = mid  # (mid,right)
            else:
                right = mid  # (left,mid)

        # left都是表示小于target的
        # right都是表示大于等于target的
        return right

    def searchRange(self, nums: List[int], target: int) -> List[int]:
        start = self.lower_bound(nums, target)
        if start == len(nums) or nums[start] != target:
            return [-1, -1]
        end = self.lower_bound(nums, target + 1) - 1
        return [start, end]
        
		'''
		总结
        # 求大于x的第一个下标,就相当于求大于等于x+1的第一个下标
        # 求小于x的最后一个下标,就相当于求大于等于x的第一个下标再-1
        # 求小于等于x的最后一个下标,就相当于求大于等于x+1的第一个下标再-1
        '''


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 。

class Solution:
    def maximumCount(self, nums: List[int]) -> int:
        # 找大于等于1的第一个下标
        # 找小于等于-1的第一个下标,就是找大于等于0的第一个下标-1
        def binary_search(nums, target):
            left = -1
            right = len(nums)
            while left + 1 != right:  # (left,right)
                mid = (left + right) // 2
                if nums[mid] < target:
                    left = mid
                else:
                    right = mid
            return right

        index1 = binary_search(nums, 1)
        pos = len(nums) - index1
        index2 = binary_search(nums, 0) - 1
        neg = index2 + 1
        return max(pos, neg)


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] 。

class Solution:
    def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]:
        potions.sort()

        def binary_search(nums, target, spell):
            left = -1
            right = len(nums)
            while left + 1 != right:
                mid = (left + right) // 2
                if nums[mid] * spell < target:
                    left = mid
                else:
                    right = mid
            return right

        ans = []
        for spell in spells:
            # 找出大于等于success*spell的第一个下标
            index = binary_search(potions, success, spell)
            ans.append(len(potions) - index)
        return ans


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) 。

class Solution:
    def countFairPairs(self, nums: List[int], lower: int, upper: int) -> int:
        nums.sort()

        def binary_search(nums, target, l, r):
            left = l
            right = r
            while left + 1 != right:
                mid = (left + right) // 2
                if nums[mid] < target:
                    left = mid
                else:
                    right = mid
            return right

        ans = 0
        for i in range(len(nums)):
            l = lower - nums[i]
            u = upper - nums[i]
            # 找出大于等于l的第一个下标
            start = binary_search(nums, l, i, len(nums))
            # 找出小于等于u的最后一个下标,就是大于等于u+1的第一个下标-1
            if 0 <= start < len(nums):
                end = binary_search(nums, u + 1, i, len(nums)) - 1

                ans += end - start + 1

        return ans


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

noruta

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值