852. 山脉数组的峰顶索引 - 力扣(LeetCode)
为什么- left初始化为1,表示左边界
- right初始化为n-2,表示右边界?
1. left 初始化为 1
因为这是一个寻找山峰的题目,数组呈现山形,左右两边一定小于中间的峰值。
所以可以初始化 left 为 1,排除 arr[0] 作为候选解,这样可以缩小查找范围。
2. right 初始化为 n-2
因为山峰不可能出现在数组最右边(不然右边就更大了),所以可以排除 arr[n-1]。
初始化 right 为 n-2 就是为了跳过这个不可能的候选。
3. 初始化的作用
这样初始化左右边界,就可以排除山峰不可能出现的两个位置,缩小了二分查找的范围,优化了时间复杂度。
4. 保证左闭右闭
left=1 和 right=n-2 也可以确保左闭右闭的区间,方便处理边界条件。
5. 和Mid计算吻合
在计算 mid 时,mid = (left + right) / 2,与 1 和 n-2 的边界初始化是吻合的。
综上,这种左右边界的初始化方式,既保证了区间的左闭右闭,也缩小了查找范围,排除了不可能的候选,优化了算法的效率。
上述代码中 arr.size是从0开始,还是从1开始?
在C++中,std::vector的size()方法返回的是向量中元素的数量,索引是从0开始的。
所以在这个代码中:
int n = arr.size();
表示的就是向量arr中元素的总个数,而不是最大索引。
举个例子,如果arr中有5个元素,那么:
- arr.size() 返回的值是5
- 元素索引范围是0~4
所以在这个代码中,n表示的是数组arr的元素总数,而不是最大索引。
数组索引arr[i]仍然是从0开始,最大索引为n-1。
为什么当 left + right = 7 时,mid 不是 4 而是 3 呢?
主要原因是在计算 mid 时使用的是整除 /,而不是普通的除法:mid = (left + right) / 2这里的 / 是整除运算符,会自动向下取整。所以当 left + right = 7 时:(left + right) / 2
= 7 / 2
= 3 (向下取整)如果是普通的除法,结果就会是 3.5,接近 4。但因为这里是整除,所以计算结果直接取整得到 3。而不是舍入后的 4。这也更符合二分查找中 midpoint 的计算方式,将中间索引看作是左右边界的中点。这种向下取整的计算方式,可以将数组对半分成两个区间,使得二分查找更加清晰。所以这里 mid 的计算采用的是整除,当 left + right = 7 时,mid 的结果是 3,而不是 4。这种向下取整的计算方式在二分查找中很常见,可以更清晰地对半分割数组区间。
用这个例子能很好的去理解整个流程。
二分
往常我们使用「二分」进行查值,需要确保序列本身满足「二段性」:当选定一个端点(基准值)后,结合「一段满足 & 另一段不满足」的特性来实现“折半”的查找效果。
但本题求的是峰顶索引值,如果我们选定数组头部或者尾部元素,其实无法根据大小关系“直接”将数组分成两段。
但可以利用题目发现如下性质:由于 arr 数值各不相同,因此峰顶元素左侧必然满足严格单调递增,峰顶元素右侧必然不满足。
因此 以峰顶元素为分割点的 arr 数组,根据与 前一元素/后一元素 的大小关系,具有二段性:
峰顶元素左侧满足 arr[i−1]<arr[i]arr[i-1] < arr[i]arr[i−1]<arr[i] 性质,右侧不满足
峰顶元素右侧满足 arr[i]>arr[i+1]arr[i] > arr[i+1]arr[i]>arr[i+1] 性质,左侧不满足
因此我们可以选择任意条件,写出若干「二分」版本。
作者:宫水三叶
链接:https://leetcode.cn/problems/peak-index-in-a-mountain-array/solutions/828434/gong-shui-san-xie-er-fen-san-fen-cha-zhi-5gfv/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
或者还有一种理解思路 就是如果你在上升阶段 我就把你左半部分砍掉 以此类推
当你刚好在顶峰的时候 就退出循环。
153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)
为什么high = pivot;?而low = pivot + 1?(可以自己思考一下)
猜想:在上面的话 一定不是我想要的 所以可以pass掉
这道题其实和上面一个题目很像。
剑指 Offer 53 - II. 0~n-1中缺失的数字 - 力扣(LeetCode)
中序与搜索树原理
嘶。。。。。。 这个和二分查找有什么关系吗?没懂
long long
为什么这个 long long maxVal = LONG_MIN; // 因为后台测试数据中有int最小值放在这个地方会报错?
这个错误可能是因为在递归调用时,每次都会重新定义一个新的maxVal变量,而不是在整个递归过程中共享同一个变量。因此,当递归返回到上一层时,maxVal的值会被重置为LONG_MIN,而不是之前的最大值。为了解决这个问题,可以将maxVal定义为类的成员变量,这样在整个递归过程中都可以共享同一个变量。