"""
整數二分要注意邊界問題 不然特別容易出現死迴圈
二分的本質是邊界問題
1.mid=(l+r)//2
2.檢查mid處是否滿足性質
在二分左邊時不需要+1 二分右邊時需要+1
二分必須要保證有解(題目可能無解,我們可以通過最後的邊界來判斷題目是否有解)
"""def
main()
: n, m =
map(
int,
input()
.split())
q =list
(map
(int
,input()
.split())
)# q = [int(x) for x in input().split()]
while m >0:
x =int(
input()
) l, r =
0, n -
1while l < r:
# 找第乙個點 判斷mid的取值是否比要找的值大 如果大的話第乙個相等值應在mid的左邊 令r=mid 否則l=mid+1
mid =
(l + r)
>>
1if q[mid]
>= x:
r = mid
else
: l = mid +
1if q[l]
!= x:
print
('-1 -1'
)else
:print
(l, end=
' ')
l, r =
0, n -
1while l < r:
# 找第二個點 判斷mid的取值是否比要找的值小 如果小的話最後乙個相等值應在mid的右邊 令l=mid 否則r=mid-1
mid =
(l + r +1)
>>
1if q[mid]
<= x:
l = mid
else
: r = mid -
1print
(l, end=
'\n'
) m -=
1if __name__ ==
'__main__'
:"""
這裡要注意邊界的問題
注意在找第乙個點的,即第乙個相等數的時候,mid的取值為(l+r)>>1
取最後乙個相等數時,mid的取值為(l+r+1)>>1
這裡記住模板就好了 具體的越界情況 有點難想emmm 跟著大哥(y總)走
"""main(
)
在找相匹配的數x的起始位置和終止位置,可以把初始的序列看成兩部分,第一部分≤x,第二部分≥x,那麼,第二部分的第乙個,即為x的起始位置(第二部分都是≥x的,),第一部分的最後乙個(第一部分都是≤x的,再大就>x了),即為終止位置。
而為了防止整數數列**現越界問題,我們可以記住y總的模板,即求初始位置(第二部分的第乙個,實質則是求數列中≥x的那部分)時,mid=(l+r+1)>>1,求終止位置(第一部分的最後乙個,即數列中≤x的那部分),mid=(l+r)>>1,不需要+1。
除此以外,求起始位置和終止位置的演算法也可以封裝成函式,然後調整乙個用法即可,下面是封裝成函式的寫法(只有函式,和上面基本一樣,只是把兩份內容單獨拎出來而已):
def
find_first
(q, l, r, x)
:"""
尋找起始位置
:param q: 數列
:param l: 數列的最左邊下標,0
:param r: 數列的最右邊下標,n-1
:param x: 要查詢的數
:return: 返回數的起始位置或者-1
"""while l < r:
mid =
(l + r)
>>
1if q[mid]
>= x:
r = mid
else
: l = mid +
1if q[l]
!= x:
return-1
else
:# 輸出結束時l和r是相等的,所以輸出哪個無所謂
return l
deffind_last
(q, l, r, x)
:"""
尋找終止位置
:param q: 數列
:param l: 數列的最左邊下標,0
:param r: 數列的最右邊下標,n-1
:param x: 要查詢的數
:return: 返回數的終止位置或者-1
"""while l < r:
mid =
(l + r +1)
>>
1if q[mid]
<= x:
l = mid
else
: r = mid -
1if q[l]
!= x:
return-1
else
:# 輸出結束時l和r是相等的,所以輸出哪個無所謂
return l
上面是整數中的二分查詢,整數中的二分查詢要注意邊界問題,相應的解決辦法提現在mid的處理上。
而在浮點數的二分法中,因為沒有整除,所以不用考慮邊界問題,思想和整數的二分法相同(就是不用考慮邊界問題),當他的區間足夠小的時候,我們就可以認為他已經是乙個數了,可以返回的l或者r處的值(此時已經「相等」了)。區間足夠小的處理上,可以這樣:
1.加上區間控制語句
while r - l >1e-
6:# 10^-6
pass
# 具體操作
2.直接將方法執行100次,次數夠多,那邊界到時候一定足夠小
for x in
range
(100):
pass
# 具體操作
相應的實際問題,求乙個數的平方根:
def
main()
:"""輸入乙個數,求它的平方根"""
x =int(
input()
) l, r =
0, x
while r - l >1e-
6:# 10^-6
mid =
(l + r)/2
if mid * mid >= x:
r = mid
else
: l = mid
print
(l)if __name__ ==
'__main__'
: main(
)
LeetCode 03 二分查詢
注意 二分查詢中關於mid的選取 while left right 和 while left right 的區別 while left right 表示在區間中還剩下乙個元素的時候,停止迴圈 來自 leetcode liweiwei1419 對於二分搜尋編碼的建議在迴圈體內考慮如何縮減待搜尋區間,也...
迭代二分查詢二分查詢
在寫這篇文章之前,已經寫過了幾篇關於改迭代二分查詢主題的文章,想要了解的朋友可以去翻一下之前的文章 bentley在他的著作 writing correct programs 中寫道,90 的計算機專家不能在2小時內寫出完整確正的二分搜尋演算法。難怪有人說,二分查詢道理單簡,甚至小學生都能明確。不過...
1128 二分 二分查詢
時間限制 10000ms 單點時限 1000ms 記憶體限制 256mb 描述nettle最近在玩 艦 因此nettle收集了很多很多的船 這裡我們假設nettle氪了很多金,開了無數個船位 去除掉重複的船之後,還剩下n 1 n 1,000,000 種不同的船。每一艘船有乙個稀有值,任意兩艘船的稀有...