数据结构与算法专题汇总(八)二分查找,查找元素第一个位置和最后一个位置,搜索旋转排序数组,跳表

二分查找数组实现

非递归实现

def bsearch(nums,n,value):
	low = 0
	high = n-1
	while low<=high:
		mid = low+(high-low)/2
		if nums[mid]==value:
			return mid
		elif nums[mid]<value:
			low = mid+1
		else:
			high = mid-1
	return -1

注意:

  1. **循环退出条件 low <= high **
  2. mid取值 (low+high)/2 可能导致溢出 可以改成
    low+(high-low/2) or low+((high-low)>>1)

递归实现

def bsearch(nums,n,value):

def bsearchHelper(nums,low,high,value):
	if low > high:
		return -1
	mid = low+(high-low)/2
	if mid == value:
		return mid
	elif mid < value:
		return bsearchHelper(nums,mid+1,high,value)
	else:
		return bsearchHelper(nums,low,mid-1,value)

局限性

  1. 依赖于顺序表结构,即数组(需要支持随机访问)
  2. 针对有序数据
    先排序,因此插入删除操作过多的场景,不适合二分,适合二叉树。
  3. 数据量太小不适合
    若数据之间的比较操作非常耗时,如300以上长度字符串比较,要可能减少比较次数,建议用二分
  4. 数据量过大不适合
    依赖于数组,需要连续的内存空间

如何在1000万个整数中快速查找某个数

  1. 二分
  2. 假设最大的是2000w,那么设置一个字节数组Byte arr[2000w]
    遍历每一个数字,x/8可得下标,x%8可得8位字节中的位数,存在置为1
    查找时只需经过x/8,x%8取得相应的bit位,就可判断该数字是否存在。

二分查找,找重复数字

def bsearch(nums,n,value):
	low = 0
	high = n-1
	while low <= high:
		mid = int(low + (high-low)/2)
		if nums[mid]>value:
			high = mid-1
		elif nums[mid]<value:
			low = mid+1
		else:
			if mid == 0 or nums[mid-1]!=value:
				return mid
			else:
				high = mid-1
	return -1

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

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        a = self.besearch(nums,target,0)
        b = self.besearch(nums,target,1))
        return [a,b]

    def besearch(self,nums,target,tag):
        low = 0
        high = len(nums)-1
        while low <= high:
            mid = int(low+(high-low)/2)
            if nums[mid] > target:
                high = mid-1
            elif nums[mid] < target:
                low = mid+1
            else:
                if tag==0:
                    if mid == 0 or nums[mid-1] != target:
                        return mid
                    else:
                        high = mid-1
                if tag==1:
                    if mid == len(nums)-1 or nums[mid+1] != target:
                        return mid
                    else:
                        low = mid+1
        return -1


大佬做法:将返回值都设为low,因为返回值是low的原因,所以要增加一个if nums[a]!=target,不等则targer不存在,直接返回[-1,-1]

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        a = self.besearch(nums,target)
        b = self.besearch(nums,target+1)
        if a ==len(nums) or nums[a]!=target:
            return [-1,-1]
        return [a,b-1]     
     
    def besearch(self,nums,target):
        low = 0
        high = len(nums)-1
        while low <= high:
            mid = int(low+(high-low)/2)
            if nums[mid] >= target:
                high = mid-1
            elif nums[mid] < target:
                low = mid+1
            else:
                if mid == 0 or nums[mid-1] != target:
                    return mid
                else:
                    high = mid-1         
        return low

leetcode 33. 搜索旋转排序数组

因为是旋转数组,只可能出现这种情况的排序
在这里插入图片描述因此取mid后,首先与nums[0]比较,若比其大,则证明左段为顺序排列的,那么只需判断target是否在左段,就可决定high和low的值;
若比其小,则表示左段是有旋转段的,那么右段肯定是顺序段,则比较mid和len(nums)-1位置的大小。

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        low = 0
        high = len(nums)-1

        while low <= high:
            mid = low+(high-low)//2
            if nums[mid]==target:
                return mid
            if nums[0] <= nums[mid]:
                if nums[0]<=target<nums[mid]:
                    high = mid-1
                else:
                    low = mid+1
            else:
                if nums[mid]<target<=nums[len(nums)-1]:
                    low = mid+1
                else:
                    high = mid-1
        return -1

658. 找到 K 个最接近的元素

二分查找链表实现—跳表

动态数据结构,可以快速支持插入,删除,查找O(logm)。
跳表—连标加多级索引的结构,也是redis的有序集合实现。

在这里插入图片描述
跳表的索引节点浪费内存?
在开发中,原始链表中存储的是很大的对象,但是索引节点只需存储关键词和指针,可忽略不计。
高效的动态插入和删除
插入数据:
在这里插入图片描述
删除数据:
需要获取前驱节点,删除原始链表结点和索引结点。
索引动态更新
通过随机函数,决定结点插入到哪几级索引中。
在这里插入图片描述
可按照区间查找数据,效率高于红黑树
同b+树??

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值