【菜鸡新手 - 牛客网刷题NC105】有重复数字的升序数组,二分查找第一个大于等于查找值的位置 - 二分查找 || 统称为找不到的情况 || python

文章目录

    • 一. 普通二分查找
        • 普通二分法伪代码
        • 普通二分法的一些个人观点:
    • 二. 本题 -- 我的解题思路


以下为原创代码,可以参考,但禁止转载!
@ author = yhr


一. 普通二分查找

(二分查找一定建立于有序数组上,以升序为例)

图 来自 牛客网 -王清楚稍有改动
【菜鸡新手 - 牛客网刷题NC105】有重复数字的升序数组,二分查找第一个大于等于查找值的位置 - 二分查找 || 统称为找不到的情况 || python_第1张图片

标记 low =0 (left) ; high = len(数组)-1 = right

普通二分法伪代码

# @ author = yhr
while low <= high:
	mid = (low+high)//2
	if v <a[mid]:
		# 去左半部分找
		high = mid -1
	elif a[mid] < v:
		# 去右半部分找
		low = mid + 1
	elif a[mid] == v:
		# 找到了一个
		return mid
return -1  # 真没找到

普通二分法的一些个人观点:

【我自己琢磨的,说不出来这个味,不对就打我吧。不确保绝对正确,但我感觉是正确的,大家可以一起琢磨琢磨,如果有数学证明就更好了!】

A. 如果查找成功,一定在 mid位置, 此时low可能 B. 如果查找失败,最后此数一定在(low-1 , low)之间。

B.1 查找失败情况一:最终当low=high=mid时,如果v B.2 查找失败情况二:最终当 low=high=mid时,如果a[mid]

这个性质就可以用到该题上:


二. 本题 – 我的解题思路

题目描述:

请实现有重复数字升序数组的二分查找。 输出在数组中 第一个 大于等于 查找值的位置,如果数组中不存在这样的数,则输出数组长度加一。
(输出位置从1开始计算)

两个主关键点: 1. 第一个 2. 大于等于
一个次关键点: 3. 输出位置从1开始计算

这里就忽略意外情况,不做细说:比如数组为空!

刚才我说,普通二分查找里,如果找不到数值v,最后他一定是在a[low-1] 与 a[low]之间!

主关键点: 1. 第一个 2. 大于等于他的数的位置,那么我们可以把大于等于统统归咎于一个情况:

在数组中,找到1. 第一个, 2.稍微大于v的位置

什么意思呢?

  • 我们把数组里所有等于v的数 都看成:v + 正无穷小,即:数组里没有等于v的数,但是 有永远比他只大一点的数

  • 那么这个题目就变成 普通二分查找里永远找不到 的情况。

  • 最后 a[low] 一定是比他大的(包括只大正无穷小的情况)第一个数的位置。

那么只需要把普通二分查找中,a[mid]==v的情况 --> 变成同a[mid]>v情况一起处理即可。

于是代码可以如此处理:

#
# 二分查找
# @param n int整型 数组长度
# @param v int整型 查找值
# @param a int整型一维数组 有序数组
# @return int整型
#
class Solution:
    def upper_bound_(self , n , v , a ):
        if len(a) ==0:
        	# 处理数组为空的情况
            return 1
        low = 0
        high = n-1
        while low <=high:
            mid = (low+high)//2
            if v <= a[mid]:
                high = mid-1
            elif v > a[mid]:
                low=mid +1

        return low +1

但是,还有些情况,我们可以直接写出来,避免代码多跑些无用功,比如:

a. 当 v 小于 整个 升序数组
b. 当 v 大于 整个 升序数组

#
# 二分查找
# @param n int整型 数组长度
# @param v int整型 查找值
# @param a int整型一维数组 有序数组
# @return int整型
#
class Solution:
    def upper_bound_(self , n , v , a ):
        if len(a) ==0:
        	# 处理数组为空的情况
            return 1
        low = 0
        high = n-1

加入两种特殊情况的处理工作,避免代码多跑无用功。

		# 加入两个特殊情况
		if v < a[low]:
			# 输出位置从1开始计算 
            return 1
        if v > a[high]:
            # 输出位置从1开始计算 
            return high+1+1
		while low <=high:
            mid = (low+high)//2
            if v <= a[mid]:
                high = mid-1
            elif v > a[mid]:
                low=mid +1
		# 输出位置从1开始计算 
        return low +1

你可能感兴趣的:(数据结构与刷题,数据结构,二分法)