数组常用方法:二分查找、双指针法、滑动窗口,二分查找主要适用于针对排序数组的查找问题
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