今天,写一篇算法的blog,主要内容由两部分:
(1)把二分法的三个基础模板和一些基本例题给过一遍;
(2)今日的LC一题,做个记录。
提示:以下是本篇文章正文内容,下面案例可供参考
先把对应的三个模板的代码给放置在这里,我们以具体地几道题来学习这三个模板,个人认为模板二是最通用的。说在最前面二分法解题的主要步骤为:1)预处理:将判断数组进行排序;2)二分查找:对数组的空间进行划分;3)后处理:确定答案。
此部分内容参考LC官方教程,参考链接为:https://leetcode.cn/leetbook/detail/binary-search/
先来解读一下三个模板的代码。
模板一:这是三个模板中代码最少的,这里需要特别记住这一行代码:mid = L + (R-L) // 2,这是为防止L与R直接计算越界的情况,例如:L=200,R=220,当存储该字节的最大值为255时,直接使用(L+R)会出现越界的情况。
//代码粘贴处
def binarySearch1(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
if len(nums) == 0:
return -1
L,R = 0, len(nums) - 1
while L <= R:
mid = L + (R-L) // 2
if nums[mid] == target:
return mid
elif nums[mid] < target:
L = mid + 1
else:
R = mid - 1
# End Condition: left > right
return -1
模板二:这是我认为最常用的模板格式,相对于模板一多了后处理阶段。
def binarySearch2(nums, target):
if len(nums) == 0: return -1
L,R = 0, len(nums) - 1
while L <= R:
mid = L + (R-L) // 2
if nums[mid] == target:
return mid
elif nums[mid] < target:
L = mid + 1
else:
R = mid
# End Condition: left == right
# post-processing:
if L != len(nums) and nums[L] == target: return L
return -1
模板三:这个模板我认为最不好用了,很容易因为逻辑不正确导致死循环。
def binarySearch3(nums, target):
if len(nums) == 0: return -1
L,R = 0, len(nums) - 1
while L+1 < R:
mid = L + (R-L) // 2
if nums[mid] == target:
return mid
elif nums[mid] < target:
L = mid
else:
R = mid
# End Condition: left+1 == right
# post-processing:
if nums[L] == target: return L
if nums[R] == target: return R
return -1
总结一下,模板二中R边界的设定与LC有一定出入,但影响不大。下面我列出几个要点说一下这三个模板的主要区别:
分享链接:
1)69 x的平方根;2)374 猜数字大小;3)33 搜索旋转排序数组
代码如下(示例):
class Solution:
def mySqrt(self, x: int) -> int:
L,R,ans = 0,x,-1
# 除法的话
if x<2: return x
while L <= R:
mid = (L+R)//2
ret = x//mid
if ret == mid:
return mid
break
elif ret > mid:
ans = mid
L = mid+1
else:
R = mid-1
return ans
'''
# 乘法算题
while L<=R:
mid = (L+R)//2
if mid * mid <= x:
ans = mid
L = mid + 1
else:
R = mid - 1
return ans
'''
分享链接:
1)278 第一个错误的版本;2)162 寻找峰值;3)153 寻找旋转排序数组的最小值。
代码如下(示例):
class Solution:
def findPeakElement(self, nums: List[int]) -> int:
L,R = 0,len(nums)-1
while L<R:
mid = L+(R-L)//2
# 就使劲找呗 往上爬坡
if nums[mid] < nums[mid+1]:
L = mid+1
else:
R = mid
return L
1)34 在排序数组中查到元素的第一个和最后一个的位置;2)658 找到k个最接近的元素。
代码如下(示例):
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
# 双指针
n = len(nums)
if n == 0 or target not in nums: return [-1,-1]
low,high = 0,n-1
while low<=high:
if nums[low] == target: low = low
else: low += 1
if nums[high] == target: high = high
else: high -= 1
if low >= 0 and high >= 0 and nums[low] == nums[high]:
return [low,high]
break
'''
# 模板三 生搬硬套有点头疼还是 双指针好用一些
if len(nums) < 1: return [-1,-1]
def binarySearch(L,R,id) -> int:
while L+1 < R:
mid = L +(R-L)//2
if nums[mid] < target and id > 0:
L = mid
elif nums[mid] <= target and id < 0:
L = mid
else:
R = mid
print(L,R)
if id > 0 :
if nums[L] == target: return L
if nums[R] == target: return R
if id < 0:
if nums[R] == target: return R
if nums[L] == target: return L
return -1
n = len(nums)
return [binarySearch(0,n-1,1),binarySearch(0,n-1,-1)]
'''
题目链接:1413. 逐步求和得到正数的最小值
要用贪心算法,挺赖皮的。
代码如下(示例):
class Solution:
def minStartValue(self, nums: List[int]) -> int:
stval,cur = 0,0
for num in nums:
cur = num+cur
stval = min(stval,cur)
return -stval+1
学习确实需要广泛地积累和总结与思考,最近看了一个科幻电影《Arrival》,虽片中有一些不好的偏见,但不可不说写这篇小说的作者思想深度非常的高,我最感兴趣的一句话分享给大家。
Despite knowing the journey … and where it leads … . I embrace it and I welcome every moment of it.