【leetcode 704、35、162、74】【二分查找法专题】

leetcode 704 【二分查找】


题目链接

https://leetcode-cn.com/problems/binary-search/


解题思路与代码思路:

二分法

关注while判断条件和right的初始赋值,当right赋值为 l e n ( n u m s ) len(nums) len(nums),那么while应该使用 < < <,搜索区间为左闭右开 [ l e f t , r i g h t ) [left,right) [left,right),索引为len(nums)是越界的;当right赋值为 l e n ( n u m s ) − 1 len(nums)-1 len(nums)1,则while应该使用 < = <= <=,搜索区间为两端都是闭区间 [ l e f t , r i g h t ] [left,right] [left,right]

关注停止搜索的判断条件,应该是如果找不到target,则搜索区间为空的时候应该终止。 w h i l e ( l e f t < = r i g h t ) while(left <= right) while(left<=right) 的终止条件是 l e f t = = r i g h t + 1 left == right + 1 left==right+1,区间为 [ r i g h t + 1 , r i g h t ] [right+1,right] [right+1,right],因为不可能存在这样的数字,所以区间为空。 w h i l e ( l e f t < r i g h t ) while(left < right) while(left<right) 的终止条件是 l e f t = = r i g h t left == right left==right,写成区间的形式就是 [ r i g h t , r i g h t ] [right, right] [right,right],这个时候区间还没空,right这一个数字并没有被搜索,会被漏掉且直接返回-1会报错。

当使用两端都是闭区间时,mid位置已经被搜索过,所以+1


代码:

二分法
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums) - 1 
        while left <= right :
            mid = left + (right - left) // 2
            if nums[mid] == target:
                return mid
            elif nums[mid] > target:
                right = mid -1
            elif nums[mid] < target:
                left = mid +1
        return -1

复 杂 度 分 析 : \color{red}{复杂度分析:}
  1. 二分法
  • 时间复杂度:O(logN)
  • 空间复杂度:O(1)

leetcode 35 【搜索插入位置】


题目链接

https://leetcode-cn.com/problems/search-insert-position/


解题思路与代码思路:

二分法

这里采用的是双端闭区间的方式,两个条件需要注意,第一个是找到了target,然后返回它的索引,第二个是找不到target,返回它应该插入的位置。通过左侧边界的写法,就可以搜寻到那个位置。

下面的代码是左侧边界的模板,只要记住左侧边界就收缩right,右侧边界就收缩left,为了避免索引溢出,要加上溢出判断条件。本题不需要返回-1,所以就不写这个判断条件


代码:

二分法(左侧边界)
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:

        left = 0
        right = len(nums) - 1 
        while left <= right :
            mid = left + (right - left) // 2
            if nums[mid] < target:
                left = mid +1
            elif nums[mid] > target:
                right = mid -1
            elif nums[mid] == target:
                right = mid - 1
        # if left >= len(nums) or nums[left] != target:
        #	return -1
        return left

复 杂 度 分 析 : \color{red}{复杂度分析:}
  1. 二分法
  • 时间复杂度:O(logN)
  • 空间复杂度:O(1)

leetcode 162 【寻找峰值】


题目链接

https://leetcode-cn.com/problems/find-peak-element/


解题思路与代码思路:

线性判断

按照题目的意思,峰值有3种情况,一个是在第一个值,一个是最后一个值,一个是在中间位置;只需要判断是否 n u m s [ i ] > n u m s [ i + 1 ] nums[i]>nums[i+1] nums[i]>nums[i+1],如果是就直接返回 i i i值,不是就一直查找。

二分查找

判断方式与线性判断是差不多的,只是为了加快搜索,通过二分的方式,就可以缩小搜索空间,只要 n u m s [ i ] > n u m s [ i + 1 ] nums[i]>nums[i+1] nums[i]>nums[i+1],则峰值就在左边区域,否则在右边,一直迭代或者递归的方式进行,直到只剩下一个元素。


代码:

线性判断
class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
    	for i in range(len(nums)-1):
			if nums[i] > nums[i+1]:
				return i
		return len(nums) - 1
二分递归写法
class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        def dfs(nums,left,right):
            if left == right:
                return left
            mid = (left+right)//2
            if nums[mid]>nums[mid+1]:
                return dfs(nums,left,mid)
            return dfs(nums,mid+1,right)


        left = 0
        right = len(nums) - 1
        return dfs(nums,left,right)

        
二分迭代写法
class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
    	left = 0
		right = len(nums)-1
		while left < right:
			mid = (left+right) // 2
			if nums[mid]>nums[mid+1]:
				right = mid
			else:
				left = mid + 1
		return left

复 杂 度 分 析 : \color{red}{复杂度分析:}
  1. 线性判断
  • 时间复杂度:O(N)
  • 空间复杂度:O(1)
  1. 二分查找法(递归)
  • 时间复杂度:O(logN)
  • 空间复杂度:O(logN)
  1. 二分查找法(迭代)
  • 时间复杂度:O(logN)
  • 空间复杂度:O(1)

leetcode 74【搜索二维矩阵】


题目链接

https://leetcode-cn.com/problems/search-a-2d-matrix/


解题思路与代码思路:

暴力法

这个方法还算可以,自己想出来的,还没有两个for循环暴力。主要是通过多重的判断来锁定一个范围。首先一个判断条件是matrix为空,然后循环矩阵的每一行,如果本行是空的,那就跳过,如果不是空,就对比target与列表的头元素和尾元素的大小,因为当target小于尾元素且大于头元素,那么就应该在这个列表中,然后判断target是否在里面,如果在就返回true。时间复杂度最坏就是遍历所有的行,O(mn),m行n列

二分查找法

在这里插入图片描述

把矩阵看成一个大的列表,因为题目说是有序的,所以可以这么做。获取元素值的方式是 r o w = i d x / / n row = idx // n row=idx//n c o l = i d x col = idx % n col=idx,套用二分法的模板,即可完成。


代码:

暴力法
class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        if not matrix:
            return False
            
        for x in matrix:
            if not x:
                continue
            if target <= x[-1]:
                if target >= x[0]:
                    if target in x:
                        return True
        return False
二分查找法
class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        m = len(matrix)
        if m == 0:
            return False
        n = len(matrix[0])
        
        #二分查找
        left, right = 0, m * n - 1
        while left <= right:
                pivot_idx = (left + right) // 2
                pivot_element = matrix[pivot_idx // n][pivot_idx % n]
                if target == pivot_element:
                    return True
                else:
                    if target < pivot_element:
                        right = pivot_idx - 1
                    else:
                        left = pivot_idx + 1
        return False


复 杂 度 分 析 : \color{red}{复杂度分析:}
  1. 暴力法
  • 时间复杂度:O(mn)
  • 空间复杂度:O(1)
  1. 二分查找法
  • 时间复杂度:O(log(mn))
  • 空间复杂度:O(1)

以上一些内容参考labuladong的博客,可以直接点击链接查看,博主很强!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值