用二分法查找循环递增序列 | Python

本文介绍了一种在循环递增序列中使用二分法查找特定元素的算法,该算法能够有效地处理这类特殊的数据结构,并确保时间复杂度为O(logN)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:

使用二分法在循环递增序列中查找指定元素,返回其下标;若不存在,则返回-1.要求时间复杂度为:O(logN)。

循环递增序列的定义:

       nums = [7,8,9,10,1,2,3,4,5,6]

       即,一个序列被分为两个子序列,每个子序列都是递增的,并且如果在指定位置(如“10”,“1”之间)切断重组,则可以变为递增序列。


思路:

注意:由于时间复杂度要求为 O(logN),则不能使用先找到断点的方法(若先找到断点,则时间复杂度必然大于O(N))。

一、我们回想一下用二分法查找递增序列:

def fun0(nums,target):
    start = 0
    end = len(nums)-1
    mid = (start+end)/2
    while start<=end:
        if target==nums[mid]:
            return mid
        if target<nums[mid]:
            end = mid-1
        else:
            start = mid+1
        mid = (start+end)/2
    return -1
    
nums = [i for i in range(10)]    
print fun0(nums,1)
具体不做赘述,主要思路是每次将列表切成两段,然后继续查找。

二、在处理循环递增列表时,我们依旧将列表先切成两段(每一个矩形代表一个递增子序列),切完之后会产生A、B两种情况:


A情况,断点位于第一个递增子序列之中,则待查找值target 可能位于上图(1)区域,或者(2)区域;若target位于(1)区域中,则可以用二分法查找;若不在,则对(2)继续切割;

B情况,断点位于第二子序列中,待查找target可能位于(3)或(4);若target位于(4)区域,则用二分法;其余情况同上。

总结:每次切割,都可以得到一个递增序列和一个循环递增序列,当发现target为递增序列中时,则可以使用二分法查找,否则,继续切割循环递增序列。

def fun(nums,target):
    start = 0
    end = len(nums)-1
      
    
    while start<=end:
        mid = (start+end)/2
        
        if target==nums[mid]:
            return mid

        if nums[start]<nums[mid]: #A情况
            if target>=nums[start] and target<=nums[mid]:  #(1)区间
                end = mid-1
            else:  #(2)区间
                start = mid+1
        if nums[mid]<nums[end]: #B情况
            if target>=nums[mid] and target<=nums[end]: #(4)区间
                start = mid+1
            else:  #(3)区间
                end = mid-1
    return -1
    
nums = [7,8,9,10,1,2,3,4,5,6]
print fun(nums,4)   



### Python 中实现二分法算法 #### 二分法算法原理 在处理有序序列时,二分法是一种高效的搜索技术。该方法通过反复将区间减半来缩小目标位置范围,从而显著减少所需比较次数[^1]。 对于给定的一个升序排列的数组`arr`和一个待查找的目标值`target`,如果中间元素正好等于目标值,则返回其索引;若大于目标值则继续在左子区间进行相同操作;反之,在右子区间重复此过程直至找到目标或者确认不存在于当前范围内[^2]。 #### 二分法代码基本实现 下面是一个简单的Python函数用于演示如何利用二分查找定位指定数值的位置: ```python def binary_search(arr, target): low, high = 0, len(arr) - 1 while low <= high: mid = (low + high) // 2 if arr[mid] == target: return mid elif arr[mid] < target: low = mid + 1 else: high = mid - 1 return -1 # 如果找不到目标值,返回-1表示未命中 ``` 这段程序定义了一个名为`binary_search`的方法接收两个参数:一个是已经排序好的整型列表`arr`,另一个是要寻找的具体数字`target`。当成功匹配到对应项时会给出它的下标作为输出结果;如果没有发现相等的情况就报告失败并给出特殊标记(-1)[^3]。 为了验证上述逻辑的有效性和准确性,这里提供了一组测试数据及其预期行为说明: 假设有一个从小到大依次递增的数据集 `[1, 3, 5, 7, 9]` 和查询请求 `7`, 那么按照上面编写的流程执行后应当得到如下所示的结果展示: ```plaintext Index of the element '7' is : 3 ``` 这表明所要找寻的对象位于原始集合中的第四个位置上(注意这里的索引起始于零)。同样地,如果我们尝试去检索不在表内的项目比如 `8` ,最终将会获得 `-1` 的反馈告知我们没有这样的成员存在于此处[^4]。 #### 应用实例——猜数游戏 除了传统的搜索应用场景之外,二分策略还可以被巧妙应用于趣味互动环节之中,例如设计一个人机对抗版“猜数字”的小游戏。在这个过程中,机器采用逐步逼近的方式不断调整自己的猜测直到完全正确为止[^5]: ```python import random def guess_number_game(): number_to_guess = random.randint(1, 100) lower_bound, upper_bound = 1, 100 attempts = 0 print("Let's play a guessing game!") while True: guessed_num = (lower_bound + upper_bound) // 2 attempts += 1 if guessed_num < number_to_guess: lower_bound = guessed_num + 1 print(f"Too small! Trying {guessed_num}.") elif guessed_num > number_to_guess: upper_bound = guessed_num - 1 print(f"Too large! Trying {guessed_num}.") else: break print(f"\nCongratulations! The correct answer was found after {attempts} tries.") guess_number_game() ``` 这个游戏模拟器内部维护着一对边界变量用来界定可能取值的空间大小,并且每次迭代都会基于最新计算出来的中心点来进行新一轮试探性的判断。一旦确定了确切的答案就会立即终止循环结构并向玩家汇报整个探索历程中总共经历了多少轮次才达成共识[^6]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值