[Alg]旋转有序数组的中二分查找

本文介绍了一种在旋转数组中查找特定元素的高效算法,通过分析中位数与旋转点的相对位置来实现logN的时间复杂度。文章详细解释了如何通过二分查找和旋转点定位来快速确定目标元素的位置。

根据中位数与旋转点相对位置查找

切分数组查找

 

给定一个没有重复元素的旋转数组(它对应的原数组是有序的),求给定元素在旋转数组内的下标(不存在的返回-1),时间复杂度为logN。
如[4,5,6,7,0,1,2]就是一个旋转数组:

  • 查找3,返回-1;
  • 查找0,返回4;

根据中位数与旋转点相对位置查找

从中位数与旋转点的相对位置看,可以有:

  • 旋转点在中位数右侧:中位数及其左侧元素全部为升序,且小于中位数;
  • 旋转点与中位数相同或在中位数左侧:中位数及其右侧元素全部升序,且大于中位数;
def searchInShiftArray(ary:list, ele:int)->int:
    def bisearch(ary, start, end):
        if start>end:
            return -1
        mid = (start+end)//2
        if ary[mid] == ele:
            return mid

        if ary[mid]>ele:
            return bisearch(ary, start, mid-1)
        else: 
            return bisearch(ary, mid+1, end)


    def search(ary, start, end):
        if start>end:
            return -1
        mid = (start+end)//2
        if ary[mid] == ele:
            return mid

        if ary[mid]<ele:            
            if ary[start]>ary[mid]: # mid在旋转点后,
                if ary[end]>=ele:
                    return bisearch(ary, mid+1, end)
                return search(ary, start, mid-1)
            # mid在旋转点前
            return search(ary, mid+1, end)
        else: # ary[mid]>ele
            if ary[start]>ary[mid]: # mid在旋转点后,
                return search(ary, start, mid-1)
            # mid在旋转点前
            if ary[start]<=ele:
                return bisearch(ary, start, mid-1)
            return search(ary, mid+1, end)

    return search(ary, 0, len(ary)-1) 

切分数组查找

查找有序数组最方便的方式是二分查找,而旋转数组也可以看作是由‘旋转点’(数组中最小元素)切分的两个有序数组。可先找到旋转点,然后分别在两个有序数组中查找即可。

查找旋转点:

def findPivotPoint(ary:list)->tuple:
    if ary[0]<ary[len(ary)-1]:
        return (False, 0, ary[0])

    def findPoint(ary:list, start, end):
        if start == end:
            return start

        mid = (start+end)//2
        if ary[mid]>ary[end]:
            return findPoint(ary, mid+1, end)
        else: #
            if ary[mid]<ary[mid-1]:
                return mid
            else:
                return findPoint(ary, start, mid-1)

    index = findPoint(ary, 0, len(ary)-1)
    return (True, index, ary[index])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值