# binary search, summary
###### tags: `interview` `binary search`
important ref: https://ojeveryday.github.io/AlgoWiki/#/BinarySearch/README?id=%e4%ba%8c%e5%88%86%e6%9f%a5%e6%89%be%e6%a8%a1%e6%9d%bf%e4%ba%8c%ef%bc%88%e6%8e%a8%e8%8d%90%ef%bc%89
先寫if-else,再決定中間數是否上取整;
在使用多了以後,就很容易記住,只要看到 left = mid ,它對應的取中位數的取法一定是 int mid = left + (right - left + 1) / 2;。
核心思想:雖然模板有兩個,但是核心思想只有一個,那就是:把待搜索的目標ele放在最後判斷,每一次循環排除掉不存在目標元素的區間,目的依然是確定下一輪搜索的區間;
特徵:while (left < right),這裡使用嚴格小於 < 表示的臨界條件是:當區間裡的元素只有 2 個時,依然可以執行循環體。換句話說,退出循環的時候一定有 left == right 成立,這一點在定位元素下標的時候極其有用;
在循環體中,先考慮 nums[mid] 在滿足什麼條件下不是目標元素,進而考慮兩個區間 [left, mid - 1] 以及 [mid + 1, right] 裡元素的性質,目的依然是確定下一輪搜索的區間;
注意 1:先考慮什麼時候不是解,確定下一輪搜索的區間,它的反面(也就是 else 語句的部分),直接從上一個分支的反面區間得到;
根據邊界情況,看取中間數的時候是否需要上取整;
在退出循環以後,根據情況看是否需要對下標為 left 或者 right 的元素進行單獨判斷,這一步叫「後處理」。在有些問題中,排除掉所有不符合要求的元素以後,剩下的那 1 個元素就一定是目標元素,可以直接返回 left(或者 right)。
:::success
while 不等於
回傳左右皆可
向右找 上高斯
向左找 下高斯
保持T
排除F
:::
## find rightmost valid element
Find the right-most T.
If it is a T, all LHS will also be T's.
```
0 1 2 3 4 5 6 7 8
T T T T T T T T T ==> 8
T T T T T T T T F ==> 7
T T F F F F F F F ==> 1
T F F F F F F F F ==> 0
F F F F F F F F F ==> -1 // no T at all
```
related problem:
https://hackmd.io/@y56/BJXStesvY
// find largest has_dup()==True
```python=
def find_rightmost_T(li):
if not li: # check special case
return -1
if li[0] != 'T': # check special case
return -1 # no T at all
# now, sure to have at least one T
left = 0
right = len(li) - 1
while left < right: # break at l == r; always use this kind of condition!
mid = (left + right) // 2 + 1
# !!! bc we want rightmost; use ceil() to RHS !!!
if li[mid] == 'T':
left = mid
# want rightmost T, mid here is T, all LHS guys are T and no longer under consideration
# nonsense for left=mid-1 since we are ignoring LHS
# nonsense for left=mid+1, maybe this mid is the rightmost; note that we will return left(same as right), if we do left=mid+1 we are ignoring the ans
else: # F
right = mid - 1
# nonsense for right=mid, note that we will return left(same as right, will be a T); we can't achieve so by keeping an F at right
# nonsense for right=mid+1; want rightmost T, mid here is F, all RHS guys are F and no longer under consideration
return left # same as right
print(find_rightmost_T('TTTT'))
print(find_rightmost_T('TTTF'))
print(find_rightmost_T('TTFF'))
print(find_rightmost_T('TFFF'))
print(find_rightmost_T('FFFF'))
print(find_rightmost_T('TTTTT'))
print(find_rightmost_T('TTTTF'))
print(find_rightmost_T('TTTFF'))
print(find_rightmost_T('TTFFF'))
print(find_rightmost_T('TFFFF'))
print(find_rightmost_T('FFFFF'))
```
## find leftmost valid element
Find the left-most T.
If it is a T, all RHS will also be T's.
```
0 1 2 3 4 5 6 7 8
T T T T T T T T T ==> 0
F T T T T T T T T ==> 1
F F T T T T T T T ==> 2
F F F F F F F T T ==> 7
F F F F F F F F T ==> 8
F F F F F F F F F ==> -1
```
related problem:
https://leetcode.com/problems/find-the-smallest-divisor-given-a-threshold/
```python=
def find_leftmost_T(li):
if not li: # check special case
return -1
if li[-1] != 'T': # check special case
return -1 # no T at all
# now, sure to have at least one T
left = 0
right = len(li) - 1
while left < right: # break at l == r; always use this kind of condition!
mid = (left + right) // 2
# !!! bc we want leftmost; use floot() to go LHS !!!
if li[mid] == 'T':
right = mid
# want leftmost T, mid here is T, all RHS guys are T and no longer under consideration
# nonsense for right=mid+1 since we are ignoring RHS
# nonsense for right=mid-1, maybe this mid is the leftmost; note that we will return left(same as right), if we do right=mid-1 we are ignoring the ans
else: # F
left = mid + 1
# nonsense for left=mid, note that we will return left(same as right, will be a T); we can't achieve so by keeping an F at left
# nonsense for left=mid-1; want leftmost T, mid here is F, all LHS guys are F and no longer under consideration
return left # same as right
print(find_leftmost_T('TTTT'))
print(find_leftmost_T('FTTT'))
print(find_leftmost_T('FFTT'))
print(find_leftmost_T('FFFT'))
print(find_leftmost_T('FFFF'))
print(find_leftmost_T('TTTTT'))
print(find_leftmost_T('FTTTT'))
print(find_leftmost_T('FFTTT'))
print(find_leftmost_T('FFFTT'))
print(find_leftmost_T('FFFFT'))
print(find_leftmost_T('FFFFF'))
```