[Python] 算法心得——二分法

二分查找也称为折半查找,要求查找的对象是顺序排列的(从小到大或者从大到小),其时间复杂度为O(log2n),下面是二分查找最简单的例子:

def binary_search(data_list, val):    
    low = 0                         # 最小数下标    
    high = len(data_list) - 1       # 最大数下标    
    while low <= high:        
        mid = (low + high) // 2     # 中间数下标        
        if data_list[mid] == val:   # 如果中间数下标等于val, 返回            
            return mid        
        elif data_list[mid] > val:  # 如果val在中间数左边, 移动high下标            
            high = mid - 1        
        else:                       # 如果val在中间数右边, 移动low下标            
            low = mid + 1    
    return # val不存在, 返回None

二分法可谓是一种非常基本的查找方法,有很多场景都可以使用到二分法,下面我们来看一下。

1. 有重复元素的二分法查找

给定一个 元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的第一个出现的target,如果目标值存在返回下标,否则返回 -1。

def search(nums , target ):
    res = -1
    if len(nums) < 1:
        return res
    low, high = 0, len(nums) - 1
    while low <= high:
        mid = (low+ high) // 2
        if nums[mid] == target:
            res = mid
            high = mid - 1   # 与传统二分法相比,多了该步骤,因为需要查找到第一次出现target元素的位置
        elif nums[mid] > target:
            high = mid - 1
        else:
            low = mid + 1
    return res
2. 求平方根
def sqrt(self , x ):
        if x < 1:
            return 0
        elif x < 4:
            return 1
        l, h = 1, x // 2
        while l <= h:
            mid = (l + h) // 2
            if mid * mid == x:
                return mid
            elif mid * mid < x:
                l = mid + 1
            else:
                h = mid - 1
        return h
3. 旋转过的有序数组中寻找目标值

给定一个整数数组nums,按升序排序,数组中的元素各不相同。
nums数组在传递给search函数之前,会在预先未知的某个下标 t(0 <= t <= nums.length-1)上进行旋转,让数组变为[nums[t], nums[t+1], ..., nums[nums.length-1], nums[0], nums[1], ..., nums[t-1]]。
比如,数组[0,2,4,6,8,10]在下标3处旋转之后变为[6,8,10,0,2,4]
现在给定一个旋转后的数组nums和一个整数target,请你查找这个数组是不是存在这个target,如果存在,那么返回它的下标,如果不存在,返回-1。

"""
与中间值比较,分前半段有序和后半段有序分别判断。比有序的二分查找多一些判定条件。
1、 要么前半段有序,要么后半段有序。
2、 当前半段有序时:即循环数组中间值比循环数组最左边值大 则 nums[left] <= nums[mid]
当target 比中间值小,比最左值(前半段最小值)大时,肯定在前面部分 则high = mid - 1 。
如果不在前半段,可能在后半段,low = mid + 1。
3、同理后半段也一样。
ps:分前半段有序后半段有序时,当nums[left] <= nums[mid] 则 left到mid有序。
否则 mid到right 有序。
"""
    def search(self , nums , target ):
        # write code here
        l, r = 0, len(nums) - 1
        while l <= r:
            mid = (l + r) // 2
            if target == nums[mid]:
                return mid
            if nums[mid] >= nums[l]:
                if (nums[mid] > target):
                    r = mid - 1
                else:
                    l = mid + 1
            else:
                if nums[mid] < target:# <= nums[r]:
                    l = mid + 1
                else:
                    r = mid - 1
                    
        return -1

你可能感兴趣的:([Python] 算法心得——二分法)