二分查找法---python語言

今天抽時間來和大家一起捋一下二分法查找的解題思路和通用模板。筆者也從leetcode上面找了幾道二分查找的題目來摸出一些類似的規律。
首先,什麼是二分查找?其實質就是折半查找,先縮小一半,再縮小一半,再一步步的縮小範圍,直至找出確定的目標。先看題目一:

https://leetcode.cn/problems/binary-search/

這是一道難度等級爲簡單級別的題目,較爲基礎,以這道經典的題目來展開深入;
解題思路:首先將這個列表中的元素,分爲兩組,左邊一半,右邊一半,然後將中間值與相鄰的元素比較大小,
如果中間值比目標值大,那就在左邊的一半里繼續找;
如果中間值比目標值小,那就在右邊的一半里繼續找:
如果中間值等於目標值,那就直接返回下標值index
如果什麼也找不到,那就在外面直接返回-1

"""
題目:給定一個n個元素有序的(升序)整型數組nums 和一個目標值target,寫一個函數搜索nums中的target,如果目標值存在返回下標,否則返回 -1
輸入: nums = [-1,0,3,5,9,12], target = 9
輸出: 4
解釋: 9 出現在 nums 中並且下標爲 4

輸入: nums = [-1,0,3,5,9,12], target = 2
輸出: -1
解釋: 2 不存在 nums 中因此返回 -1
"""


def search(nums, target):
    left, right = 0, len(nums) - 1  # 雙閉區間
    while left <= right:  # 由於是雙閉區間,決定了當退出循環的條件是left>right的時候,如果不帶等號可能會遺漏
        mid = left + (right - left) // 2  # 可以防止left+right過大導致加和溢出問題
        # 其實,求中間值的方法,mid = (left+right)//2 也是可以的,等同於上面那一行,但是可能會出現數據過大而造成的溢出問題
        if nums[mid] == target:  # 找到目標即可返回
            return mid
        elif nums[mid] < target:
            # 如果中間值比目標值小,比較過後,那就可以直接在另一半里面找了,之前左側那一半元素可以直接棄掉,此時以left=mid+1爲左側邊界,重新開始找
            left = mid + 1
        elif nums[mid] > target:
            # 同理,如果中間值比目標值大,比較過後,那就可以直接在另一半里面找了,之前右側那一半元素可以直接棄掉,此時以right=mid-1爲右側邊界,重新開始找
            right = mid - 1
    # 如果裏面的判斷條件還查找不到,那就直接返回-1
    return -1

 我把每一步的執行過程都在稿紙尚一步一步的寫出來,請看以上拍照截圖

 請繼續看第二題:

https://leetcode.cn/problems/search-insert-position/

 這道題和上一道題幾乎相類似,就是多了一個插入的元素,並顯示下標值

"""
二分查找插入列表中的題目
給定一個排序數組和一個目標值,在數組中找到目標值,並返回其索引。如果目標值不存在於數組中,返回它將會被按順序插入的位置
輸入: nums = [1,3,5,6], target = 5
輸出: 2

輸入: nums = [1,3,5,6], target = 2
輸出: 1

輸入: nums = [1,3,5,6], target = 7
輸出: 4
"""


def searchInsert(nums, target):
    left, right = 0, len(nums) - 1  # 雙閉區間
    while left <= right:  # 由於是雙閉區間,決定了當退出循環的條件是left>right的時候,如果不帶等號可能會遺漏
        mid = left + (right - left) // 2  # 可以防止left+right過大導致加和溢出問題
        if nums[mid] == target:  # 找到目標即可返回
            return mid
        elif nums[mid] < target:
            left = mid + 1
        elif nums[mid] > target:
            right = mid - 1
    return right + 1

 

 請繼續看第三題:

https://leetcode.cn/problems/valid-perfect-square/   有效的完全平方數

"""
二分查找:有效的完全平方數
給定一個 正整數 num ,編寫一個函數,如果 num 是一個完全平方數,則返回 true ,否則返回 false
最好不好使用任何的內置函數sqrt等
"""
def isPerfectSquare(self, num: int) -> bool:
    if num == 0:
        return True
    if num == 1:
        return True
    left= 0
    right = num
    while left <= right:
        mid = (left + right) // 2
        if mid * mid == num:
            return True
        elif mid * mid > num:
            right = mid - 1
        else:
            left = mid + 1
    return False

 

再看第四題:

https://leetcode.cn/problems/sqrtx/    x的平方數

"""
二分法:
給你一個非負整數 x ,計算並返回 x 的 算術平方根 。
由於返回類型是整數,結果只保留 整數部分 ,小數部分將被 捨去
輸入:x = 4
輸出:2

輸入:x = 8
輸出:2     只保留整數部分
"""

def mySqrt(self, x: int) -> int:
    left = 0
    right = x
    while left <= right:
        mid = left + (right - left) // 2
        # 確定命中區間
        if mid * mid <= x:
            if (mid + 1) * (mid + 1) <= x:  # 如果下一個元素的平方還小於x 則假命中
                left = mid + 1
            else:
                return mid  # 否則 真命中 直接返回
        else:
            right = mid - 1

 

請看最後一題:

https://leetcode.cn/problems/peak-index-in-a-mountain-array/   山脈數組

"""
山脈數組
輸入:arr = [0,2,1,0]
輸出:1

輸入:arr = [0,10,5,2]
輸出:1

輸入:arr = [3,4,5,1]
輸出:2

輸入:arr = [24,69,100,99,79,78,67,36,26,19]
輸出:2
"""


def peakIndexInMountainArray(arr):
    left = 1
    right = len(arr) - 2
    ans = 0
    while left <= right:
        mid = left + (right - left) // 2
        if arr[mid] > arr[mid + 1]:
            ans = mid
            right = mid - 1
        else:
            left = mid + 1
    return ans

 

所以從以上5道題中,基本可以摸出二分查找的規律了,left與right的邏輯處理尤爲重要

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章