二分法模板(基础篇)+ 2022.8.9-每日一题(贪心)
前言
今天,写一篇算法的blog,主要内容由两部分:
(1)把二分法的三个基础模板和一些基本例题给过一遍;
(2)今日的LC一题,做个记录。
提示:以下是本篇文章正文内容,下面案例可供参考
一、二分法模板(基础篇)
1.三个模板的对比及介绍
先把对应的三个模板的代码给放置在这里,我们以具体地几道题来学习这三个模板,个人认为模板二是最通用的。说在最前面二分法解题的主要步骤为: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有一定出入,但影响不大。下面我列出几个要点说一下这三个模板的主要区别:
- End Condition:这是最大的区别,模板一不需要访问左右边界(nums[L]与nums[R]),模板二需要访问右边界(nums[R]),模板三则访问两个边界;
- Post-processing:模板二和模板三都需要进行后处理判断决定是否使用(nums[L]与nums[R]);
- 主要区别就是上面两点,其实具体到while函数中也有局部不同,但这都是由于End Condition所决定的,所以需要联系起来具体分析,不能死记硬背。
2.常见例题的模板应用
2.1 模板一
分享链接:
1)69 x的平方根;2)374 猜数字大小;3)33 搜索旋转排序数组
- 这里我们就仅说一下 69 x的平方根。
- 题意:给你一个非负整数 x ,计算并返回 x 的 算术平方根 。 由于返回类型是整数,结果只保留 整数部分 。
代码如下(示例):
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
'''
2.2 模板二
分享链接:
1)278 第一个错误的版本;2)162 寻找峰值;3)153 寻找旋转排序数组的最小值。
- 这里我们就仅说一下162 寻找峰值。
- 题意:峰值元素是指其值严格大于左右相邻值的元素。 给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个峰值 所在位置即可。
- 时间复杂度为 O(log n)。
代码如下(示例):
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
2.3 模板三
1)34 在排序数组中查到元素的第一个和最后一个的位置;2)658 找到k个最接近的元素。
- 这里我们就仅说一下162 寻找峰值
- 题意:给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。
- 时间复杂度为 O(log n)。
代码如下(示例):
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)]
'''
二、2022.8.9-每日一题(贪心)
题目链接:1413. 逐步求和得到正数的最小值
- 题意:给你一个整数数组 nums 。你可以选定任意的 正数 startValue 作为初始值。你需要从左到右遍历 nums 数组,并将 startValue 依次累加上 nums 数组中的值。请你在确保累加和始终大于等于 1 的前提下,选出一个最小的 正数 作为 startValue 。
要用贪心算法,挺赖皮的。
代码如下(示例):
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.