【算法】二分查找

概念


   二分查找的对象必须是一个有序的数据集合,这有点类似于分治思想。每次都是通过和区间中间的元素进行比较,然后根据规则将查找区间缩小为原先的一半,直到找到需要查找的元素。由于每一次我们都是向数据集合的大小缩小为一半,因此二分查找的时间复杂度为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

 

posted @ 2019-04-02 15:44  GoodRnne  阅读(387)  评论(0编辑  收藏  举报