Q57- code1095- 山脉数组中查找目标值
实现思路
1 方法1:通用二分法
1.1 通过quickFind,快速找到分割点pdx
1.2 依次对(-1, pdx) 和 (pdx, len) 有序区间,进行二分查找
1.3 开区间表示 当前未处理的元素不包括 边界值
2 本题技巧:
- 可以通过抽象出quickFind里的condition方法,来复用二分查找
- 二分查找的重点是 找到分割点
参考文档
代码实现
1 方法1- 通用二分法
- 时间复杂度:O(logn)
- 空间复杂度:O(1)
function findInMountainArray(target: number, arr: MountainArray): number {
const len = arr.length();
// 找峰值:第一个非递增的分割点
const pdx = quickFind(-1, len, (i) => arr.get(i) > arr.get(i + 1));
if (arr.get(pdx) === target) return pdx;
// >=t的最小值(左侧升序部分)
const ldx = quickFind(-1, pdx, (i) => arr.get(i) >= target);
if (arr.get(ldx) === target) return ldx;
// <=t的最大值(右侧降序部分)
// 易错点1:如果这里是>=t,会导致错误的更新r边界,而不是更新l边界
// 易错点2: 最后的返回值需要加上pdx的偏移量
const rdx = pdx + quickFind(-1, len - pdx, (i) => arr.get(pdx + i) <= target);
return arr.get(rdx) === target ? rdx : -1;
}
function quickFind(l: number, r: number, condition: (i: number) => boolean) {
while (l + 1 < r) {
const mid = l + ((r - l) >> 1);
if (condition(mid)) {
r = mid;
} else {
l = mid;
}
}
return r;
}
Q58- code162- 寻找峰值
实现思路
1 方法1:二分查找
1.1 根据题目,总共有3种可能
- 有序-降序:峰值就是第 0个元素,因为题目保证了nums[-1] = -∞
- 有序-升序:峰值就是第 n-1个元素,因为题目保证了nums[n] = -∞
- 无序- 即有峰值的情况:此时可以通过 idx 和 idx+1位置,进行比较
-
如果 nums[idx] < nums[idx + 1],那么必然 [idx+1, n-1]会存在峰值 (由于我们不需要求 所有峰值中的最大峰值,所以可以放心排除掉 idx+1之前的所有值)
-
同理,如果 nums[idx] > nums[idx + 1],那么必然 [0, idx]会存在峰值
-
2.1 二分本质:
- 二分的本质 不是有序性/ 单调性
- 而是 通过某种条件/性质,确定答案在哪一侧(从而每次都可 排除掉一半的搜索空间)
2.2 二分开区间写法 表示的含义
- left 和 right表示的是,在[left+1,right-1]之间的 都是不能确定所属关系的元素;
- left 和 right本身,是能确定所属关系的元素,所以不包括在内,是开区间
2.3 常见二分场景
- 峰值/谷值:找局部最大/最小值
- 旋转数组:找局部最大/最小值
- 第K个问题:求最大/最小的 满足条件的值
参考文档
代码实现
1 方法1- 通用二分法
- 时间复杂度:O(logn)
- 空间复杂度:O(1)
function findPeakElement(nums: number[]): number {
// 易错点1:
// 理论上:按开区间语义,r应该设置为len
// 实际上:因为本题需要和 nums[mid+1]进行比较,必须保证mid+1不越界
// 所以 本题妥协方案:设置 r = len - 1,虽然破坏了开区间的完美语义,但避免了越界
const len = nums.length;
let l = -1, r = len - 1;
while (l + 1 < r) {
const mid = (l + r) >> 1;
if (nums[mid] < nums[mid + 1]) {
l = mid;
} else {
// 此时 nums[mid] 必然> nums[mid + 1],峰值范围一定在[0, mid]之间
// 因为 题目保证了 nums[i] != nums[i + 1]
r = mid;
}
}
return r;
}