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