一个整数矩阵有如下一些特性:
相邻的整数都是不同的
矩阵有 n 行 m 列。
对于所有的 i < m, 都有 A[0][i] < A[1][i] && A[n - 2][i] > A[n - 1][i].
对于所有的 j < n, 都有 A[j][0] < A[j][1] && A[j][m - 2] > A[j][m - 1].
我们定义一个位置 P 是一个峰,如果有 A[j][i] > A[j+1][i] && A[j][i] > A[j-1][i] && A[j][i] > A[j][i+1] && A[j][i] > A[j][i-1]。
找出该矩阵的一个峰值元素,返回它的坐标。
注意事项
可能会存在多个峰值,返回任意一个即可。
思路
从中间行的最大值往上或下寻找比该元素更大的值攀爬,从而使矩阵在 O(n) 的时间操作下规模减小了一半,然后在刚刚元素所在列寻找最大值,对当前规模为原来一半的矩阵进行重复的寻找操作
代码
// O(m + n) 算法
// 利用 flag 来对行列进行交替二分,flag = true 时二分行,flag = false 时二分列
// 每一次递归调用 x1, x2, y1, y2 都会更新
class Solution {
/**
* @param A: An integer matrix
* @return: The index of the peak
*/
public List<Integer> find(int x1, int x2, int y1, int y2,
int[][] A, boolean flag) {
if (flag) {
int mid = x1 + (x2 - x1) / 2;
int index = y1;
for (int i = y1; i <= y2; ++i) {
if (A[mid][i] > A[mid][index]) {
index = i;
}
}
if (A[mid - 1][index] > A[mid][index]) {
return find(x1, mid - 1, y1, y2, A, !flag);
}
else if (A[mid + 1][index] > A[mid][index]) {
return find(mid + 1, x2, y1, y2, A, !flag);
}
else {
return new ArrayList<Integer>(Arrays.asList(mid, index));
}
} else {
int mid = y1 + (y2 - y1) / 2;
int index = x1;
for (int i = x1; i <= x2; ++i) {
if (A[i][mid] > A[index][mid]) {
index = i;
}
}
if (A[index][mid - 1] > A[index][mid]) {
return find(x1, x2, y1, mid - 1, A, !flag);
}
else if (A[index][mid + 1] > A[index][mid]) {
return find(x1, x2, mid + 1, y2, A, !flag);
}
else {
return new ArrayList<Integer>(Arrays.asList(index, mid));
}
}
}
public List<Integer> findPeakII(int[][] A) {
int n = A.length;
int m = A[0].length;
return find(1, n - 2, 1, m - 2, A, true);
}
}