(二分查找)Leetcode34. 在排序数组中查找元素的第一个和最后一个位置+74. 搜索二维矩阵

首先要明确二分查找算法如何实现,是采用左闭右闭还是左闭右开

左闭右闭

第⼀种写法,我们定义 target 是在⼀个在左闭右闭的区间⾥,也就是 [left, right] (这个很重要⾮常重要)

区间的定义这就决定了⼆分法的代码应该如何写,因为定义 target [left, right]区间,所以有如下两点:

while (left <= right) 要使⽤ <= ,因为left == right是有意义的,所以使⽤ <=

if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]⼀定不是target,那么接

下来要查找的左区间结束下标位置就是 middle - 1

左开右闭

如果说定义 target 是在⼀个在左闭右开的区间⾥,也就是[left, right) ,那么⼆分法的边界处理⽅式则截然不同。

有如下两点:

while (left < right),这⾥使⽤ < ,因为left == right在区间[left, right)是没有意义的

if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻

找,⽽寻找区间是左闭右开区间,所以right更新为middle,即:下⼀个查询区间不会去⽐较nums[middle]

复杂度:对于长度为n的数组,最坏情况下需要进行log₂n次比较操作。每次操作的时间复杂度为O(1),因此总的时间复杂度为对数阶O(log n)

74. 搜索二维矩阵

74. 搜索二维矩阵 - 力扣(LeetCode)

python 复制代码
class Solution(object):
    def searchMatrix(self, matrix, target):
        """
        :type matrix: List[List[int]]
        :type target: int
        :rtype: bool
        """
        m=len(matrix)#行
        n=len(matrix[0])#列
        #每一个编号可以为n*行号+列号
        left=0
        right=m*n-1
        while(left<=right):
            middle=(left+right)/2
            loclm,locrm=middle/n,middle-middle/n*n
            #loclm,locrm=middle//n,middle%n
            if matrix[loclm][locrm]==target:
                return True
            elif matrix[loclm][locrm]>target:
                right=middle-1
            else:
                left=middle+1
        return False   

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

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

相当于找一个框可以包住target数组,比如[5,7,7,8,8,10]target=8的例子就是希望能找到[7,8,8,10]这个框

寻找target在数组里的左右边界,有如下三种情况:

  • 情况一:target 在数组范围的右边或者左边,例如数组{3, 4, 5},target为2或者数组{3, 4, 5},target为6,此时应该返回{-1, -1}
  • 情况二:target 在数组范围中,且数组中不存在target,例如数组{3,6,7},target为5,此时应该返回{-1, -1}
  • 情况三:target 在数组范围中,且数组中存在target,例如数组{3,6,7},target为6,此时应该返回{1, 1}

这三种情况都考虑到,说明就想的很清楚了。

接下来,在去寻找左边界,和右边界了。

采用二分法来去寻找左右边界,两个二分来寻找左边界和右边界。

代码随想录

为了避免上面的情况,所以需要初始化为-2而不是-1

rightborder=-2,leftborder=-2

python 复制代码
class Solution(object):
    def searchRange(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        left=0
        right=len(nums)-1
        #左闭右闭查找方式
        #相当于找一个框可以包住target数组,比如[5,7,7,8,8,10]target=8的例子就是希望能找到[7,8,8,10]这个框
        rightborder=-2
        leftborder=-2
        #leftborder查找
        while left<=right:
            middle=(left+right)/2
            if target>nums[middle]:
                left=middle+1
            elif target<=nums[middle]:
                right=middle-1
                #这里更新跟随等号走,并且更新为right而不是middle
                leftborder=right
        #rightborder查找
        #重新初始化
        left=0
        right=len(nums)-1
        while left<=right:
            middle=(left+right)/2
            if target>=nums[middle]:
                left=middle+1
                rightborder=left
            elif target<nums[middle]:
                right=middle-1
        if rightborder ==-2 or leftborder ==-2:
            return [-1,-1]
        #区间长度至少为2
        elif rightborder-leftborder>1:
            return [leftborder+1,rightborder-1]
        else:
            return [-1,-1]