python蓝桥杯学习-二分查找

一、二分查找的介绍

1、二分查找的概念

二分查找(Binary Search)是一种在有序无重复数组中查找特定元素的搜索算法。

二分查找的基本思想是:

  1. 将整个有序数组分成前、中、后三个部分;

  1. 先比较中间部分元素是否等于要查找的元素,如果相等则查找成功;

  1. 否则如果中间部分元素大于要查找的元素,则在前半部分元素中继续查找;

  1. 如果中间部分元素小于要查找的元素,则在后半部分元素中继续查找。

重复以上过程,直到找到要查找的元素,或者查找范围为空。

2、二分查找的例子

如图,假设有一个长度为4的有序无重复元素数组,初始时,数组的左指针left指向数组第一个元素1,即下标为0的元素,数组的右指针right指向数组最后一个元素12,即下标为数组长度-1的元素,数组的中间指针mid指向中间的元素6,即下标为数组长度之和/2的元素

假设要查找的数字是6,则此时mid正是要查找的值的下标,直接返回mid下标值,表示找到了这个元素;假设要查找的数字是4,此时mid指向的值是6,显然是大于4的,则需要调整的是右指针right,将右指针的范围改为mid前面(至于right=mid还是mid-1涉及到区间的选择,左闭右开还是左闭右闭);假设要查找的数字是9,此时mid指向的值是6,显然是小于12的,则需要调整的是左指针left,将左指针的范围改为mid之后(至于left=mid还是mid+1也是涉及到了区间的选择)

3、二分查找的特点

  • 被查找的需要是有序数组

  • 二分查找的时间复杂度为O(log n)。

二、二分查找的代码

1、代码思路

二分查找的区间有左闭右开和左闭右闭,首先是以左闭右闭为例的代码步骤:

  1. 定义左右指针,left和right,初始化left=0,right=len(nums)-1,这里len(nums)-1指的是数组长度-1

  1. 定义while循环,当左指针小于等于右指针,即left<=right时(在左闭右闭的区间中,left可以等于right,如[1,1]是合理的只有一个元素的区间),则进入区间的判断

  1. 定义mid,指向中间值,mid=left+(right-left)// 2

  1. 接着进入值的判断,

  1. 如果指向的值等于要查找的值,即nums[mid]==target,说明指向的值就是要查找的值,直接返回mid的值,return mid

  1. 如果指向的值小于要查找的值,即nums[mid]<target,说明需要调整左区间的范围位于mid之后,left=mid+1,为什么+1?此时nums[mid]已经小于target了,说明中间的值肯定是小于要查找的值的,区间肯定是在这个值之后的。

  1. 最后的情况肯定是剩下指向的值大于要查找的值了,即nums[mid]>target,说明要调整右区间,right=mid-1,-1的原理和+1是相似的,区间肯定是位于这个值之前的。

2、注意事项

二分查找的代码需要注意几个点:

  • 二分查找的数组需要是有序的,如果原数组不是有序的,可以用sort()排序后进行查找

  • 注意middle得取值溢出得情况: 如果left和right都是两个极大int类型 ,那可能存在溢出得情况。所以要注意 middle = left + (right-left)//2

  • 如果没有查到需要的值,返回其他的值(如-1,看题目具体需要)

3、具体代码参考

三、具体题目

题目1

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。原题:704. Binary Search - 力扣(Leetcode)

解题思路:这个题需要注意的是有序数组,可以直接使用二分查找来完成。

解题代码:

class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        left = 0
        right = len(nums) - 1
        while(left <= right):
            middle = left + (right - left) // 2
            if nums[middle] > target:
                right = middle - 1 
            elif nums[middle] < target:
                left = middle + 1
            else:
                return middle
        return -1

题目2

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。请必须使用时间复杂度为 O(log n) 的算法。35. 搜索插入位置 - 力扣(Leetcode)

解题思路:这道题给了排序数组且需要复杂度为O(log n)的算法,可以考虑二分查找,基本上和题目1是相同的,但是返回值有所不同,这里要返回的是需要插入的位置

解题步骤:

  1. 定义左右指针,初始化

  1. 进入循环,定义中间值指针,判断中间值与目标值,如果相等直接返回(因为题目中说如果相同直接返回下标值);中间值大于目标值,说明要插入到中间值以后的位置,调整左指针,反之调整右指针;如果循环结束没有找到目标值,说明要插入到最后。

  1. 最终都是返回left,即第一个大于等于目标值的元素。

解题代码:

class Solution(object):
    def searchInsert(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        left,right = 0,len(nums)-1
        while left <= right:
            mid = left + (right - left) // 2
            if nums[mid] == target:
                return mid 
            elif nums[mid] > target:
                right = mid - 1
            else:
                left = mid + 1
        return left

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值