算法入门--二分查找

        二分查找:给定一个有序数组,需要查找目标值的位置。

        思路,每次比较目标值与数组中间位置值,根据比较结果来返回目标值位置(nums[mid]==target),或者改变数组的左边界、右边界,或者返回-1(数组中不存在target)。

        代码如下:

class Solution:
    def search(self,nums:list[int],target:int)->int:
        #初始化左右边界
        left,right=0,len(nums)-1

        while left<=right:
            #每次循环取区间的中点
            mid=(left+right)//2
            #如果恰好等于则返回下标
            if nums[mid]==target:
                return mid
            #根据结果改编查找的区间
            elif nums[mid]<target:
                left=mid+1
            else:
                right=mid-1
        #未搜索到target        
        return -1

        理解了基础的思路之后,在使用中需要考虑更多的细节:

                1、区间的开闭        2、mid 如何取值        3、出界条件        4、搜索区间如何变化

        1、区间  (l为左边界,r为右边界)

                左闭右闭:初始化l=0,r=len(nums)-1

                左闭右开:初始化l=0,r=len(nums) 

                在写的时候左闭右开的写法不可以取到右边界上的点,左闭右闭则可以取到两个边界点,建议使用左闭右闭

        2、mid取值

                mid=(l+r)//2                -(1)

                mid=(l+r+1)//2            -(2)    

                mid=l+(r-l)//2               -(3)

                mid=l+(r-l+1)//2           -(4)

                先说第一第二个写法,元素个数是奇数时没有区别,他们的区别是个数为偶数时,(1)会取到中间靠左的元素,(2)取到中间靠右的元素;

                (3)、(4)是与(1)、(2)对应的写法,可以防止整型溢出(py中没有)

        3、出界条件

                l<=r                -(5)

                l<r                  -(6)

                条件为(5)时,循环结束l=r+1,也就遍历了数组的所有区间。使用条件(6)的话需要将return改为 return l if nums[l] == target else -1

        4、搜索区间:

               l=mid+1,r=mid-1        -(7)

               l=mid+1,r=mid           -(8)

               l=mid,r=mid-1            -(9)

               没太懂,但是好像(7)够用了

话不多说,上题目

704、二分查找

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        l,r=0,len(nums)-1

        while(l<=r):
            m=(l+r)//2
            if nums[m]==target:
                return m
            elif nums[m]<target:
                l=m+1
            else:
                r=m-1
        return -1

35、搜索插入位置

        与上一题相似,如果数组中没有target值的话需要返回插入位置,循环条件是l<=r,因此数组中没有target值的时候l=r+1正好是插入位置,return l 即可

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        l,r=0,len(nums)-1

        while(l<=r):
            m=(l+r)//2
            if nums[m]==target:
                return m
            elif nums[m]<target:
                l=m+1
            else:
                r=m-1
        return l

374、猜数字大小  

class Solution:
    def guessNumber(self, n: int) -> int:
        l,r=1,n

        while(l<=r):
            m=(l+r)//2
            if (guess(m)==0):
                return m
            elif (guess(m)==1):
                l=m+1
            else:
                r=m-1
        return -1

69、x的平方根 输出m时需要添加条件(m+1)**2>x,确定x是在m^2,(m+1)^2之间

class Solution:
    def mySqrt(self, x: int) -> int:
        l,r=0,46340
        while(l<=r):
            m=(l+r)//2
            m_2=m*m
            if (m_2<=x and (m+1)**2>x):
                return m
            elif m_2<x:
                l=m+1
            else:
                r=m-1
        return -1    

167、两数之和2 思路与暴力差不多,遍历数组的每一个元素,对于每一个元素,对后面的区间进行二分查找。

class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        for i in range(len(numbers)-1):

            left,right=i+1,len(numbers)-1

            while left<=right:
                #每次循环取区间的中点
                mid=(left+right)//2
                #如果恰好等于则返回下标,注意加一
                if numbers[mid]+numbers[i]==target:
                    return [i+1,mid+1]
                #根据结果改变查找的区间
                elif numbers[mid]+numbers[i]<target:
                    left=mid+1
                else:
                    right=mid-1
            #未搜索到target        
        return -1

1011、在D天内送达包裹的能力

详解在注释中,主要是循环条件的写法;使用d和cur记录;变区间的条件与区间如何变化(这一点其实不太理解)

class Solution:
    def shipWithinDays(self, weights: List[int], days: int) -> int:
        #二分查找,确定查找区间:目标重量在数组最大值和数组和之间
        l = max(weights)
        r = sum(weights)
        
        #循环结束是l==r 是要输出的容量
        while l < r:
            #根据题目新加d,cur记录天数和当前的容量
            d=1
            cur=0
            mid = (l +r) // 2
            #对于数组中的数,如果相加后大于mid则将目前的weight留到下一天
            for weight in weights:
                if cur+weight>mid:
                    d+=1
                    cur=0
                cur+=weight
            #如果要求的天数days < d 这次循环对应的天数,则将重量变大,对应的天数d减小
            
            #排除掉不符合的区间
            if days<d:
                l=mid+1
            else:
                r=mid
        return l

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值