二分查找法---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的逻辑处理尤为重要

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