• 【算法】二分查找


    概念


       二分查找的对象必须是一个有序的数据集合,这有点类似于分治思想。每次都是通过和区间中间的元素进行比较,然后根据规则将查找区间缩小为原先的一半,直到找到需要查找的元素。由于每一次我们都是向数据集合的大小缩小为一半,因此二分查找的时间复杂度为O(nlog n)。相对于遍历查找时间效率高出很多(当然这只是在数据集合比较大的时候(内存能装下),当数据集合较小的时候,遍历查找和二分查找的速率差别不是很大)。

    实现代码



    1
    def divided_find(nums, tar): 2 if len(nums) < 1: # 数组为空直接返回 3 return 0 4 start , end = 0, len(nums)-1 5 6 while start <= end: # 循环判断条件 7 mid = start + ((end-start)>>1) # 取中间的元素 8 if nums[mid] == tar: # 如果直接相等的话直接返回结果 9 return True 10 elif nums[mid] > tar: # 中间元素大于tar,则end提前 11 end = mid - 1 12 else: 13 start = mid + 1 14 return False # 查找不到,返回False

        注意:1)循环退出条件(start <= end, 不能写成 start < end)。2)mid的求值我们使用了mid = start + ((end-start)>>1) 而没有使用常规的(start + end)//2 ,因为(start+ end) 有可能会存在溢出的情况,所以选择另一种办法,还有就是使用>> 来代表除法,加快运算效率。3)每次缩小时,都是使用mid- 1 or mid +1 , 因为如果使用start = mid 之类的话,会导致死循环。

    几个关于二分查找经典的问题


      一、查找第一个值等于给定值的元素。(在有序的数组中存在重复的值,查找给定元素值第一个出现的位置)

        解决代码(思路主要是和前面得一样,但是因为是求第一个出现的位置,所以当nums[mid]等于tart时,需要进行判断以下):

     1 def divided_find(nums, tar):
     2     if len(nums) < 1:
     3         return 0
     4     start, end = 0, len(nums)-1 
     5     while start <= end: 
     6         mid = start + ((end-start)>>1)
     7         if nums[mid] > tar:               
     8             end = mid -1
     9         elif nums[mid] < tar:
    10             start = mid + 1
    11         else:
    12             if mid == 0 or nums[mid-1] != tar:          # 改变的地方,如果mid等于0的话,直接返回。 否则判断该数字前面位置是否相等。
    13                 return mid
    14             end = mid-1
    15     return False

      二、查找最后一个值等于给定值的元素。(在有序的数组中存在重复的值,查找给定元素值最后一个出现的位置)

        解决代码(思路主要是和前面得一样,但是因为是求最后一个出现的位置,所以当nums[mid]等于tart时,需要进行判断以下):

     1 def divided_find(nums, tar):
     2     if len(nums) < 1:
     3         return 0
     4     start, end = 0, len(nums)-1
     5     while start <= end:
     6         mid = start + ((end-start)>>1)
     7         if nums[mid] > tar:
     8             end = mid -1
     9         elif nums[mid] < tar:
    10             start = mid + 1
    11         else:
    12             if mid == end or nums[mid+1 ] != tar:
    13                 return mid
    14             start = mid + 1
    15     return False

      三、查找第一个值大于等于给定值的元素。(在有序的数组中存在重复的值,查找给定元素第一个值大于等于出现的位置)

        解决代码:

     1 def divided_find(nums, tar):
     2     if len(nums) < 1:
     3         return 0
     4     start, end = 0, len(nums)-1
     5     while start <= end:
     6         mid = start + ((end-start)>>1)
     7 
     8         if nums[mid] >= tar:                    # 当元素大于或者等于目标元素时,我们对其进行判断。
     9             if mid == 0 or nums[mid-1] < tar:
    10                 return mid
    11             end = mid - 1
    12         else:
    13             start = mid + 1
    14     return False

      三、查找最后一个值小于等于给定值的元素。(在有序的数组中存在重复的值,查找给定元素最后一个值小于等于出现的位置)

        解决代码:

     1 def divided_find(nums, tar):
     2     if len(nums) < 1:
     3         return 0
     4     start, end = 0, len(nums)-1
     5     while start <= end:
     6         mid = start + ((end-start)>>1)
     7 
     8         if nums[mid] <= tar:
     9             if mid == end or nums[mid+1] > tar:
    10                 return mid
    11             start = mid + 1
    12         else:
    13             end = mid - 1
    14     return False
  • 相关阅读:
    非递归遍历二叉树Java
    【滴滴实习】滴滴2023届产研秋招储备实习生正在火热招募中🔥
    c++从office word的xml源文本文件中提取空行后的首个段落
    自建脚本安装docker
    银河麒麟安装软件失败,可使用命令行安装
    Fiddler+Proxifier抓pc应用包(c/s架构)
    11. Spring高级AOP概念
    10. Spring高级IOC的深入剖析
    12. Spring高级注解驱动AOP开发入门
    9. Spring高级注解驱动开发入门
  • 原文地址:https://www.cnblogs.com/GoodRnne/p/10643024.html
Copyright © 2020-2023  润新知