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}{复杂度分析:} 复杂度分析:
- 二分法
- 时间复杂度: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}{复杂度分析:} 复杂度分析:
- 二分法
- 时间复杂度: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}{复杂度分析:} 复杂度分析:
- 线性判断
- 时间复杂度:O(N)
- 空间复杂度:O(1)
- 二分查找法(递归)
- 时间复杂度:O(logN)
- 空间复杂度:O(logN)
- 二分查找法(迭代)
- 时间复杂度: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}{复杂度分析:} 复杂度分析:
- 暴力法
- 时间复杂度:O(mn)
- 空间复杂度:O(1)
- 二分查找法
- 时间复杂度:O(log(mn))
- 空间复杂度:O(1)