【菜雞新手 - 牛客網刷題NC105】有重複數字的升序陣列,二分查詢第一個大於等於查詢值的位置 - 二分查詢 || 統稱為找不到的情況 || python
文章目錄
以下為原創程式碼,可以參考,但禁止轉載!
@ author = yhr
一. 普通二分查詢
(二分查詢一定建立於有序陣列上,以升序為例)
圖 來自 牛客網 -王清楚,稍有改動
標記 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可能<high。也可能low=high=mid。
B. 如果查詢失敗,最後此數一定在(low-1 , low)之間。
B.1 查詢失敗情況一:最終當low=high=mid時,如果v<a[mid],那麼high-=1,此時v一定在 a[high]=a[low-1] 與 a[low]之間。
B.2 查詢失敗情況二:最終當 low=high=mid時,如果a[mid]<v,那麼low+=1,此時v一定在 a[high]=a[low-1] 與 a[low]之間。
這個性質就可以用到該題上:
二. 本題 – 我的解題思路
題目描述:
請實現有重複數字的升序陣列的二分查詢。 輸出在陣列中 第一個 大於等於 查詢值的位置,如果陣列中不存在這樣的數,則輸出陣列長度加一。
(輸出位置從1開始計算)
兩個主關鍵點: 1. 第一個 2. 大於等於
這裡就忽略意外情況,不做細說:比如陣列為空!
剛才我說,普通二分查詢裡,如果找不到數值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