Leetcode 162/1901. 寻找峰值I/II

(4 mins to read)

I

一个元素互不相同的一维数组,要求$O(\log n)$找到一个峰值,即大于左右两边值的位置。a[-1]和a[n]可认为是$-\infty$。

考虑二分答案mid,如果a[mid] > a[mid + 1],在[l, mid - 1]间肯定存在答案,因为可以把mid + 1视作n这个角色;同理a[mid] < a[mid + 1],在[mid + 1, r - 1]间肯定有答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
impl Solution {
pub fn find_peak_element(nums: Vec<i32>) -> i32 {
let n = nums.len();
let mut l = 0;
let mut r = n - 1;
let mut ans = 0;
while l <= r {
let mid = (l + r) >> 1;
let left = if mid == 0 {
true
} else {
nums[mid] > nums[mid - 1]
};
let right = if mid == n - 1 {
true
} else {
nums[mid] > nums[mid + 1]
};
if left && right {
ans = mid;
break;
} else if left {
l = mid + 1;
} else if right {
r = mid - 1;
} else {
l = mid + 1;
}
}
ans as i32
}
}

II

二维版本,要求$O(n \log m)$。没做出来0.0,好菜

考虑二分行mid,再考虑这一行中的最大值a[mid][j],如果a[mid][j] < a[mid + 1][j],则行[mid + 1, r - 1]肯定有答案,因为a[mid + 1][j]大于mid行的所有元素,而由于不断往比自己大的邻居移动一定能找到解,按这种方案一定不会穿越mid行;同理a[mid][j] < a[mid - 1][j],则行[l, mid - 1]肯定有答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
impl Solution {
pub fn find_peak_grid(mat: Vec<Vec<i32>>) -> Vec<i32> {
let mut l = 0;
let mut r = mat.len() - 1;
while l <= r {
let mid = (l + r) >> 1;
let index = mat[mid].iter().enumerate()
.max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
.map(|(index, _)| index).unwrap();
if mid >= 1 && mat[mid][index] < mat[mid - 1][index] {
r = mid - 1;
continue;
}
if mid + 1 < mat.len() && mat[mid][index] < mat[mid + 1][index] {
l = mid + 1;
continue;
}
return vec![mid as i32, index as i32];
}
vec![]
}
}