教程:https://github.com/youngyangyang04/leetcode-master
二分法
- 时间复杂度:O(logx),即为二分查找需要的次数。
- 空间复杂度:O(1)。
牛顿迭代法
- 时间复杂度:O(log x),此方法是二次收敛的,相较于二分查找更快。
- 空间复杂度:O(1)。
- 公式:(x+a/x)/2。(遇到平方根都可以考虑牛顿迭代法)
34.在排序数组中查找元素的第一个和最后一个位置(中等)
链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/
题目描述:给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:
你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
if(len(nums)==0):
return [-1,-1]
l , r = 0, len(nums)-1
left = right = -1
while(l <= r):
m = l + (r - l) // 2
if(nums[m] == target):
left = right = m
break
if(nums[m] < target):
l = m + 1
if(nums[m] > target):
r = m - 1
if(left != -1):
while(m - 1 >= 0 and nums[m-1] == target):
m = m - 1
left = m
while(m + 1 < len(nums) and nums[m+1] == target):
m = m + 1
right = m
return [left,right]
思路:二分查找,查到一个,往左右两边用while去寻找是否有更小更大的值。
官方解:定义一个boolen值的lower,定义一个函数,将list和target传进去算leftIndex 和 rightIndex。
注意:考虑边界问题(l > 0 and r < length)。
35.搜索插入位置(简单)
链接:https://leetcode-cn.com/problems/search-insert-position/
题目描述:给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。你可以假设数组中无重复元素。
解法:就是普通的二分查找法。由于 >= 时,只移动right,当 middle == target 时,right在下一轮移动到 < lefr,left 不变,所以最后返回 left 即可。(使用这种方法就不用判断边界,边界判断不恰当反而会报错)
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
l , r = 0 , len(nums)-1
while(l<=r):
mid=l+(r-l)//2
if(nums[mid]<target):
l=mid+1
else:
r=mid-1
return l
注意:
- nums数组与target比较时用 nums[m] == target
- left, right加减middle
- 插入第一个元素的时候,判断 right<0 而不是 right<=0 (不需要判断边界问题)
复杂度分析
- 时间复杂度:O(logx),即为二分查找需要的次数。
- 空间复杂度:O(1)。
69.x的平方根(简单)
链接:https://leetcode-cn.com/problems/sqrtx/solution/niu-dun-die-dai-fa-by-loafer/
解法1:普通的二分查找法,由于根取整数,找到比middle小的那一个即可。由于结束条件是left > right, 所以最后一轮迭代时,right即我们要求的值。
解法2:牛顿迭代法。(x+a/x)/2。(遇到平方根都可以考虑牛顿迭代法)
#二分法
class Solution:
def mySqrt(self, x: int) -> int:
left,right = 1,x
while(left <= right):
mid = left + (right - left) // 2
if(mid * mid <= x):
left = mid + 1
if(mid * mid == x):
return mid
if(mid * mid > x): #不要偷懒用else(报错!!!)
right = mid - 1
return (right)
#牛顿迭代法
class Solution:
def mySqrt(self, x: int) -> int:
if x == 0:
return 0
C, x0 = float(x), float(x)
while True:
xi = 0.5 * (x0 + C / x0)
if abs(x0 - xi) < 1e-7:
break
x0 = xi
return int(x0)
复杂度分析
- 时间复杂度:O(log x),此方法是二次收敛的,相较于二分查找更快。
- 空间复杂度:O(1)。
367.有效的完全平方数(简单)
链接:https://leetcode-cn.com/problems/valid-perfect-square/
解法1:普通的二分法。用了2种方法实现(全闭,左开右闭)
解法2:牛顿迭代法
#左闭右开
class Solution:
def isPerfectSquare(self, num: int) -> bool:
if(num<2):
return True
left = 2
right = num // 2 + 1
while left < right:
x = ( right + left) // 2
if(x*x == num):
return True
elif(x*x < num):
left = x + 1
else:
right = x
return False
# 迭代法
class Solution:
def isPerfectSquare(self, num: int) -> bool:
if num < 2:
return True
x = num // 2
while x * x > num:
x = (x + num // x) // 2
return x * x == num
704.二分查找(简单)
链接:https://leetcode-cn.com/problems/binary-search/
题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
思路:最简单的二分法。
# JS实现的
var search = function(nums, target) {
let l = 0, r = nums.length - 1;
while(l <= r){
let m = (r+l) >> 1;
if(target === nums[m]){
return m;
}
else if (target < nums[m]){
r = m - 1;
}
else{
l = m + 1;
}
}
return -1;
};