【LeetCode】二分专题

目录

 

注意:

模板

69. x 的平方根

35. 搜索插入位置

34. 在排序数组中查找元素的第一个和最后一个位置

74. 搜索二维矩阵

153. 寻找旋转排序数组中的最小值

33. 搜索旋转排序数组

278. 第一个错误的版本

162. 寻找峰值

287. 寻找重复数

275. H指数 II


注意:

主要和b站大雪菜一起刷题,宝藏up主(https://www.bilibili.com/video/BV1Ft41157zW

模板

  • 确定二分的边界
  • 编写二分的代码框架
  • 设计一个check(性质)
  • 判断一下区间如何更新
  • 如果更新方式写的是l=mid,r=mid-1,那么就在算mid的时候+1
# 模板1
while l<r:
    mid = (l+r)>>2
    if 性质:
        l = mid + 1
    else:
        r = mid
retrun l

# 模板2
while l<r:
    mid = (l+r+1)>>2
    if 性质:
        l = mid
    else:
        r = mid - 1

69. x 的平方根

思路:

  • 最后答案取的是x的向下取整
  • 利用t^2<=x将整个[0,x]划成两个部分,[0,t][t+1,x]
class Solution:
    def mySqrt(self, x: int) -> int:
        l,r = 0, x
        while l < r:
            mid = (l+r+1)>>1
            if  mid<=x/mid:
                l = mid
            else:
                r = mid-1
        return l

35. 搜索插入位置

思路:

  • 利用模板,寻找插入位置。
  • 因为数组是递增序列,若数组为空,则直接插入到0,若数组最后一个数比target小,则插入到末尾
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        if not nums or target>nums[-1]:
            return len(nums)
        l,r = 0, len(nums)-1
        while l<r:
            mid = (l+r)//2
            if nums[mid]>=target:
                r = mid
            else:
                l = mid+1
        return r

34. 在排序数组中查找元素的第一个和最后一个位置

思路:

  • 寻找第一个和最后一个位置
  • 第一个位置寻找设置的check性质为:t>=target,寻找这个的左端点
  • 最后一个位置寻找设置的check性质为:t<=target,寻找这个的右端点
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        if not nums:
            return [-1,-1]
        l, r = 0, len(nums)-1
        # 寻找左端点
        while l<r:
            mid = (l+r)>>1
            if nums[mid]>=target:
                r = mid
            else:
                l = mid + 1
        start = l
        if nums[start]!=target:
            return [-1,-1]
        # 寻找右端点
        l, r = 0, len(nums)-1
        while l<r:
            mid = (l+r+1)>>1
            if nums[mid] <= target:
                l = mid
            else:
                r = mid - 1
        end = l
        return [start, end]

74. 搜索二维矩阵

思路:

  • 将这个二维矩阵看成一个一维的0~n*m-1且满足递增的序列
  • 然后直接套二分法做即可,这里的check(性质):t>=target,我们需要寻找的是这个区间的最左端点
class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        if len(matrix)==0 or len(matrix[0])==0:
            return False
        m, n = len(matrix), len(matrix[0])
        l, r = 0, m*n-1
        while l<r:
            mid = (l+r)>>1
            if matrix[mid//n][mid%n]>=target:
                r = mid
            else:
                l = mid+1
        if matrix[l//n][l%n]!=target:
            return False
        return True

153. 寻找旋转排序数组中的最小值

思路:

  • 找到一个性质将这个排序数组分成两段,这里选用check(性质):t<=nums[-1],目标是寻找这段区间的最左端点
class Solution:
    def findMin(self, nums: List[int]) -> int:
        l,r = 0, len(nums)-1
        while l < r:
            mid = (l+r)>>1
            if nums[mid]<=nums[-1]:
                r = mid
            else:
                l = mid+1
        return nums[l]

33. 搜索旋转排序数组

思路:

  • 上一题是要求寻找旋转后的排序数组里的最小值,这题是寻找旋转后的排序数组target的下标
  • 不能直接用性质划成两段,可以先寻找target在旋转后的前一段,还是后一段里,因为在这某一段里面仍然是单调的
  • 可以用上一题的方法先找到旋转数组中的最小值的坐标,判断一下target和nums[-1]的大小关系,即可知道target在哪一段里,在在这里一段里用二分法即可
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if not nums:
            return -1
        # 寻找最小值的坐标
        l, r = 0, len(nums)-1
        while l < r:
            mid = (l+r)>>1
            if nums[mid]<=nums[-1]:
                r = mid
            else:
                l = mid+1
        if nums[-1]>=target:# [0, 1, 2]
            r = len(nums)-1
        else:# [4,5,6,7]
            l,r = 0, r-1
        while l<r:
            mid = (l+r)>>1
            if nums[mid]>=target:
                r = mid
            else:
                l = mid+1
        if nums[l] != target:
            return -1
        return l

278. 第一个错误的版本

思路:

  • 有[1,2....n]个版本号,寻找第一个错误的版本
  • 这里利用二分模板,它的check也已经给了函数,所以只需要套模板即可
# The isBadVersion API is already defined for you.
# @param version, an integer
# @return a bool
# def isBadVersion(version):

class Solution:
    def firstBadVersion(self, n):
        """
        :type n: int
        :rtype: int
        """
        l, r = 1, n
        while l<r:
            mid = (l+r)>>1
            if isBadVersion(mid):
                r = mid
            else:
                l = mid + 1
        return l

162. 寻找峰值

思路:

  • 峰值指的就是其两边的值比它小,用二分法寻找这个峰值的话,可以想象在这个峰值之前的数比它小,在这个峰值之后的数比它小
  • 这里语言可能描述不太清楚,可以看下大雪菜的视频,画图之后更好理解。lc 162. Find Peak Element 106:39
class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        l,r = 0, len(nums)-1
        while l<r:
            mid = (l+r)>>1
            if nums[mid]>nums[mid+1]:
                r = mid
            else:
                l = mid+1
        return l

287. 寻找重复数

思路:

  • 利用抽屉原理做,苹果数如果大于抽屉数,就一定有多余的
  • 同理,如果统计的个数大于这个区间应该的长度,就一定有重复的数字
class Solution:
    def findDuplicate(self, nums: List[int]) -> int:
        l,r = 1, len(nums)
        while l<r:
            mid = (l+r)>>1
            cnt = 0
            for num in nums:
                if num<=mid and num>=l:
                    cnt += 1
            if cnt > mid-l+1:
                r = mid
            else:
                l = mid+1
        return l

275. H指数 II

思路:

  • lc 275. H-Index II 129:47
class Solution:
    def hIndex(self, citations: List[int]) -> int:
        l,r=0,len(citations)
        while l<r:
            mid = (l+r+1)>>1
            if citations[len(citations)-mid]>=mid:
                l = mid
            else:
                r = mid-1
        return l

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值