算法与数据结构:数组——二分查找题解总结

库函数实现二分查找

对于非降序数组nums和需要查找的目标值target,可以使用Python3中的库函数bisect进行查找。有三种用法,输入都是一个列表和需要查找的元素:

index1 = bisect(nums, target)
index2 = bisect_left(nums, target)
index3 = bisec_right(nums, target)

其中bisect()和bisect_right()两者是等价的。总共有如下三种情况:

  • target不在nums中:三者返回值相同,都是插入后使原数组有序的位置
import bisect
nums = [1,5,9,13,17]
index1 = bisect.bisect(nums,7)
index2 = bisect.bisect_left(nums,7)
index3 = bisect.bisect_right(nums,7)
print("index1 = {}, index2 = {}, index3 = {}".format(index1, index2, index3))
#输出 index1 = 2, index2 = 2, index3 = 2
  • target在nums中唯一:左等、右加一
    如果列表中只有一个元素等于target,那么bisect_left(nums, target)的值是target在nums中的索引,nums[index2] = target。而bisec_right(nums, target)的值是target在nums中的索引加1,ls[index3] > target。
import bisect
nums = [1,5,9,13,17]
index1 = bisect.bisect(nums,9)
index2 = bisect.bisect_left(nums,9)
index3 = bisect.bisect_right(nums,9)
print("index1 = {}, index2 = {}, index3 = {}".format(index1, index2, index3))
# 输出: index1 = 3, index2 = 2, index3 = 3
  • target在nums中不唯一:左等左、右等右加一
    如果列表中存在多个元素等于target,那么bisect_left(nums, target)返回最左边的那个索引,此时nums[index2] = target。bisec_right(nums, target)返回最右边的那个索引加1,此时ls[index3] > target。
import bisect
nums = [1,5,5,5,17]
index1 = bisect.bisect(nums,5)
index2 = bisect.bisect_left(nums,5)
index3 = bisect.bisect_right(nums,5)
print("index1 = {}, index2 = {}, index3 = {}".format(index1, index2, index3))
# 输出 index1 = 4, index2 = 1, index3 = 4

注意事项:

  1. 数组必须是非降序排列好的,才能使用上述库函数
  2. 刷题时可能要自己实现特殊功能,因此还需要知道上述库函数是如何实现的。
  3. 注意区分三者的差别:中和右等价,右总是加一

代码实现库函数功能

def my_bisect(nums, k):
	#查找元素是否存在,存在则返回某一个索引,不存在则返回-1
    i, j = 0, len(nums)
    while i < j:
        mid = i + ((j-i) >> 1)
        if nums[mid] > k:
            j = mid
        elif nums[mid] < k:
            i = mid+1
        else:
		    return i
	return -1

def bisect_left(nums, k):
	# 返回最左边的索引
    i, j = 0, len(nums)
    while i < j:
        mid = i + ((j-i) >> 1)
        if nums[mid] >= k:
            j = mid
        else:
            i = mid+1
    return i

def bisect_right(nums, k):
	# 返回最右边的索引加一
    i, j = 0, len(nums)
    while i < j:
        mid = i + ((j-i) >> 1)
        if nums[mid] <= k:
            i = mid+1
        else:
            j = mid
    return i

二分法易错点:区间概念不清!

二分法容易出错主要是由于区间问题分不清楚,这里引用代码随想录中的总结,一共有两种区间方式:左闭右闭和左闭右开。一般使用左闭右开会更好。两者代码如下:

class Solution:
	#左闭右闭
    def search(self, nums: List[int], target: int) -> int:
        left, right = 0, len(nums) - 1
        
        while left <= right:
            middle = (left + right) // 2

            if nums[middle] < target:
                left = middle + 1
            elif nums[middle] > target:
                right = middle - 1
            else:
                return middle
        return -1

class Solution:
	#左闭右开
    def search(self, nums: List[int], target: int) -> int:
        left,right  =0, len(nums)
        while left < right:
            mid = (left + right) // 2
            if nums[mid] < target:
                left = mid+1
            elif nums[mid] > target:
                right = mid
            else:
                return mid
        return -1

参考文献:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值