[LintCode] Find Peak Element II
There is an integer matrix which has the following features:
- The numbers in adjacent positions are different.
- The matrix has n rows and m columns.
- For all i < m, A[0][i] < A[1][i] && A[n - 2][i] > A[n - 1][i].
- For all j < n, A[j][0] < A[j][1] && A[j][m - 2] > A[j][m - 1].
We define a position P is a peek if 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].
Find a peak element in this matrix. Return the index of the peak.
Given a matrix:
[
[1 ,2 ,3 ,6 ,5],
[16,41,23,22,6],
[15,17,24,21,7],
[14,18,19,20,10],
[13,14,11,10,9]
]
return index of 41 (which is [1,1]
) or index of 24 (which is [2,2]
)
The matrix may contains multiple peeks, find any of them.
Solve it in O(n+m) time.
If you come up with an algorithm that you thought it is O(n log m) or O(m log n), can you prove it is actually O(n+m) or propose a similar but O(n+m) algorithm?
http://www.lintcode.com/en/problem/find-peak-element-ii/
二分查找!
1 class Solution { 2 public: 3 /** 4 * @param A: An integer matrix 5 * @return: The index of the peak 6 */ 7 vector<int> findPeakII(vector<vector<int> > A) { 8 // write your code here 9 vector<int> res; 10 int left = 0, right = A.size() - 1; 11 while (left <= right) { 12 int mid = left + ((right - left) >> 1); 13 int col = findPeak(A[mid]); 14 if (A[mid][col] < A[mid+1][col]) { 15 left = mid + 1; 16 } else if (A[mid][col] < A[mid-1][col]) { 17 right = mid - 1; 18 } else { 19 return {mid, col}; 20 } 21 } 22 return res; 23 } 24 int findPeak(vector<int> &v) { 25 int res = 0; 26 for (int i = 1; i < v.size(); ++i) { 27 if (v[i] > v[res]) res = i; 28 } 29 return res; 30 } 31 };
下面是错误的,但是居然AC了,数据好弱啊。
这题跟杨氏矩阵有点像,可以使用杨氏矩阵的思想,因为题目已经说时了第二行第二列倒数第二行倒数第二列肯定比第一行第一列倒数第一行倒数第一列的元素大,那么我们只需从第二行第二列开始寻找,因为要找peek element,所以要跟四周元素比较,如果发现有比它大的元素,那么就移动到比它大的元素的坐标。如果有右侧与下侧都比它大,那么就移到更大的那一个元素那儿,这样就可以保证下一个比当前元素大的元素只可能出现在右侧或下侧。因为我们只会向右或向下移动,所以最坏的情况就是移动到右下角,但时间复杂度还是O(N+M)。
1 class Solution { 2 public: 3 /** 4 * @param A: An integer matrix 5 * @return: The index of the peak 6 */ 7 bool isOK(vector<vector<int> > &A, int i, int j) { 8 if (i < 1 || i >= A.size() - 1 || j < 1 || j >= A[0].size() - 1) 9 return false; 10 return A[i][j] > A[i][j-1] && A[i][j] > A[i-1][j] 11 && A[i][j] > A[i][j+1] && A[i][j] > A[i+1][j]; 12 } 13 14 vector<int> findPeakII(vector<vector<int> > A) { 15 // write your code here 16 vector<int> res; 17 int i = 1, j = 1; 18 while (i < A.size() - 1 && j < A[0].size() - 1) { 19 if (isOK(A, i, j)) { 20 res.push_back(i); 21 res.push_back(j); 22 return res; 23 } else { 24 if (A[i+1][j] > A[i][j+1]) ++i; 25 else ++j; 26 } 27 } 28 return res; 29 } 30 };