题目 1901. 寻找峰值 II
难度 : 中等
题目大意:
一个 2D 网格中的 峰值 是指那些 严格大于 其相邻格子(上、下、左、右)的元素。
给你一个 从0
开始编号 的m x n
矩阵mat
,其中任意两个相邻格子的值都不相同 。找出 任意一个 峰值mat[i][j]
并 返回其位置[i,j]
。
你可以假设整个矩阵周边环绕着一圈值为-1
的格子。
要求写出 O ( n l o g m ) O(nlogm) O(nlogm) 或者 O ( m l o g n ) O(mlogn) O(mlogn)的算法
提示:
- m == mat.length
- n == mat[i].length
- 1 <= m, n <= 500
- 1 <= mat[i][j] <= 105
- 任意两个相邻元素均不相等.
思路1:暴力做法
- 我们可以仿照这题 162. 寻找峰值 题解 ,我们只要从一个点出发,然后 ⌈ \lceil ⌈依据人往高处走 ⌉ \rceil ⌉的想法只需要判断四个方向,然后哪里高就往哪里走,最后走不了的时候就直接返回结果
代码实现:
class Solution {
public:
vector<int> findPeakGrid(vector<vector<int>>& mat) {
int n = mat.size(), m = mat[0].size();
int x = 0, y = 0;
while (true) {
if (x + 1 < n && mat[x + 1][y] > mat[x][y]) {
x += 1;
continue;
}
if (x - 1 >= 0 && mat[x - 1][y] > mat[x][y]) {
x -= 1;
continue;
}
if (y + 1 < m && mat[x][y + 1] > mat[x][y]) {
y += 1;
continue;
}
if (y - 1 >= 0 && mat[x][y - 1] > mat[x][y]) {
y -= 1;
continue;
}
return {x, y};
}
return {};
}
};
时间复杂度 O ( n m ) O(nm) O(nm)
思考怎么优化呢?依据题目给的时间复杂度,要把一个维度优化为 O ( l o g n ) O(logn) O(logn)级别,那么是不是可以考虑和 162. 寻找峰值 题解 的优化思路一样考虑二分呢?
思路二 :二分法
- 这个我们根据什么来判断二分的区间呢?类比 162. 寻找峰值 题解 的思考方法,以每一行(列)的最大值来判断二分的区间,假设下标为
(i, j)
,根据暴力的思路,我们判断这个点上下的值,即grid[i - 1][j] 和 grid[i][j] 和 grid[i + 1][j]
但是要判断一下边界,我们往高处走,这一行的最大值是(i, j)
那么说明之后的二分的过程中,只能在i
的一侧, 不可能从一侧跨到另外一测 - 但是为什么这个是正确的呢?
贴一个LeetCode官方题解的证明:官方题解证明
代码实现:
class Solution {
public:
vector<int> findPeakGrid(vector<vector<int>>& mat) {
int n = mat.size(), m = mat[0].size();
auto check = [&](int mid) -> bool {
int j = max_element(mat[mid].begin(), mat[mid].end()) - mat[mid].begin();
return !mid || mat[mid - 1][j] < mat[mid][j];
};
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
int idx = max_element(mat[l].begin(), mat[l].end()) - mat[l].begin();
return {l, idx};
}
};
时间复杂度 O ( m l o g n ) O(mlogn) O(mlogn)
- 库函数
max_element(first, second)
简介
定义在range
头文件里面,第一个参数是起始位置, 第二个参数是结束位置,返回值是这一段区间内的最大值的位置(迭代器)
【微语】哪怕是一点点进步,也比停滞不前要好。