Leetcode刷题笔记 - 数组(二分查找)

本文详细介绍了二分查找算法在LeetCode几道经典题目中的应用,包括704二分查找、35搜索插入位置、34在排序数组中查找元素的第一个和最后一个位置、69x的平方根以及367有效的完全平方数。分别展示了左闭右闭和左闭右开两种区间处理方式,并提供了暴力枚举的对比方法。
摘要由CSDN通过智能技术生成

数组常用方法:二分查找、双指针法、滑动窗口,二分查找主要适用于针对排序数组的查找问题

Leetcode704 二分查找

【题目描述】

【可用方法】

1.方法一:暴力枚举

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        for i in range(len(nums)):
            if nums[i] == target:
                return i
        return -1

2.方法二:二分查找(左闭右闭区间)

二分查找的前提:排序数组(升序或者降序)

定义两个循环变量left,right,根据区间的中间值nums[mid]与目标值target的大小关系,在循环过程调整区间,最终return需要的答案(因为区间的定义是左闭右闭的,所以left==right有意义,循环条件为left<=right)

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

3.方法三:二分查找(左闭右开区间)

因为区间的定义是左闭右开的,所以left==right没有意义,循环条件为left<right,此时右边界的更新变为right=mid,因为right=mid-1会导致nums[mid-1]被忽略

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

【相关题目】

35 搜索插入位置

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

69 x 的平方根

367 有效的完全平方数


Leetcode35 搜索插入位置

【题目描述】

和704题类似,适合用二分查找做

【可用方法】

1.方法一:暴力枚举

根据题目所给示例和提示,nums为无重复元素升序数组,因此根据目标值与数组元素的大小关系可以大致分为三种情况:1)目标值小于数组第一个元素,因此插入位置为数组第一个元素之前,因此返回值为0;2)目标值大于数组最后一个元素,因此插入位置为数组最后一个元素之后,返回值为len(nums);3)目标值位于数组元素之间,如果数组元素等于目标值,则返回索引位置,如果不等于,则记录数组元素比目标值小的位置存在pos变量中,根据升序数组特性,直到循环结束,此时pos记录的索引位置为<target的最后一个元素的位置,因此返回pos+1即可

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        if nums[0] > target:
            return 0
        if nums[-1] < target:
            return len(nums)
        for i in range(len(nums)):
            if nums[i] == target:
                return i
            if nums[i] < target: 
                pos = i + 1
        return pos

2.方法二:二分查找(左闭右闭区间)

方法同704题,区别在于如果找不到目标值,704题返回的是-1,而这里返回的是在数组中的插入位置,因此return left,至于为什么是left,可以代入方法一给出的两种特殊情况来确定

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

3.方法三:二分查找(左闭右开区间)

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

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

【题目描述】

【可用方法】

1.方法一:暴力枚举

enumerate()函数:返回一个可迭代对象的索引与值,常结合for循环进行遍历操作

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        res = []
        for i,val in enumerate(nums):
            if val == target:
                res.append(i)
        if not res:
            return [-1,-1]
        return [res[0], res[-1]]

2.方法二:二分查找

二分查找的第一道中等题,最大的难点是数组存在重复元素且需要找两个位置索引,具体的思路是写两个函数,分别查找左右边界,在查找的时候要注意,找到目标值以后还要继续搜索,直到找到满足条件(第一次出现或者最后一次出现)的位置索引

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:  
        if nums == None or len(nums) == 0 or target > nums[-1] or target < nums[0]:
            return [-1,-1]
        l = self.leftRange(nums,target)
        r = self.rightRange(nums,target)
        return [l,r]
    
    def leftRange(self,nums,target):
        left, right = 0, len(nums)-1
        while(left <= right):
            mid = left + (right-left)//2
            if nums[mid] < target:
                left = mid + 1
            if nums[mid] == target:
                right = mid - 1
            if nums[mid] > target:
                right = mid - 1
        if (nums[left] == target):
            return left
        else:
            return -1

    def rightRange(self,nums,target):
        left, right = 0, len(nums)-1
        while(left <= right):
            mid = left + (right-left)//2
            if nums[mid] < target:
                left = mid + 1
            if nums[mid] == target:
                left = mid + 1
            if nums[mid] > target:
                right = mid - 1
        if (nums[right] == target):
            return right
        else:
            return -1

3.方法三:二分查找(左闭右开区间)

没写

Leetcode69 x 的平方根

【题目描述】

【可用方法】

1.方法一:暴力枚举

class Solution:
    def mySqrt(self, x: int) -> int:
        if x == 0 or x == 1:
            return x
        for i in range(x+1):
            if i ** 2 > x:
                break
        return i-1

2.方法二:二分查找(左闭右闭区间)

这道题的关键在于我们要找到使得mid*mid<=x的最大的数,因此当mid*mid<=num时,除了更新区间还要更新答案ans

class Solution:
    def mySqrt(self, x: int) -> int:
        l, r, ans = 0, x, -1
        while(l<=r):
            mid = l + (r-l) // 2
            if mid * mid <= x:
                l = mid + 1
                ans = mid
            else:
                r = mid - 1
        return ans

3.方法三:二分查找(左闭右开区间)

class Solution:
    def mySqrt(self, x: int) -> int:
        l, r, ans = 0, x+1, -1
        while(l<r):
            mid = l + (r-l) // 2
            if mid * mid <= x:
                l = mid + 1
                ans = mid
            else:
                r = mid
        return ans

Leetcode367 有效的完全平方数

【题目描述】

 【可用方法】

1.方法一:暴力枚举

class Solution:
    def isPerfectSquare(self, num: int) -> bool:
        for i in range(num):
            if i ** 2 == num:
                return True
        return False

注:暴力法运行超时了!

2.方法二:二分查找(左闭右闭区间)

类似于69题 x 的平方根,区别在于这道题要找到是否有平方等于num的数,因此mid*mid<num和mid*mid=num要分开写

class Solution:
    def isPerfectSquare(self, num: int) -> bool:
        l, r = 0, num
        while(l <= r):
            mid = l + (r - l) // 2
            if mid * mid == num:
                return True
            if mid * mid < num:
                l = mid + 1
            else:
                r = mid - 1
        return False

3.方法三:二分查找(左闭右开区间)

class Solution:
    def isPerfectSquare(self, num: int) -> bool:
        l, r = 0, num + 1
        while(l < r):
            mid = l + (r - l) // 2
            if mid * mid == num:
                return True
            if mid * mid < num:
                l = mid + 1
            else:
                r = mid
        return False

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值