Welcome to Subscribe On Youtube

1901. Find a Peak Element II

Description

A peak element in a 2D grid is an element that is strictly greater than all of its adjacent neighbors to the left, right, top, and bottom.

Given a 0-indexed m x n matrix mat where no two adjacent cells are equal, find any peak element mat[i][j] and return the length 2 array [i,j].

You may assume that the entire matrix is surrounded by an outer perimeter with the value -1 in each cell.

You must write an algorithm that runs in O(m log(n)) or O(n log(m)) time.

 

Example 1:

Input: mat = [[1,4],[3,2]]
Output: [0,1]
Explanation: Both 3 and 4 are peak elements so [1,0] and [0,1] are both acceptable answers.

Example 2:

Input: mat = [[10,20,15],[21,30,14],[7,16,32]]
Output: [1,1]
Explanation: Both 30 and 32 are peak elements so [1,1] and [2,2] are both acceptable answers.

 

Constraints:

  • m == mat.length
  • n == mat[i].length
  • 1 <= m, n <= 500
  • 1 <= mat[i][j] <= 105
  • No two adjacent cells are equal.

Solutions

Solution 1: Binary Search

Let $m$ and $n$ be the number of rows and columns of the matrix, respectively.

The problem asks us to find a peak, and the time complexity should be $O(m \times \log n)$ or $O(n \times \log m)$. Therefore, we can consider using binary search.

We consider the maximum value of the $i$-th row, and denote its index as $j$.

If $mat[i][j] > mat[i + 1][j]$, then there must be a peak in the rows $[0,..i]$. We only need to find the maximum value in these rows. Similarly, if $mat[i][j] < mat[i + 1][j]$, then there must be a peak in the rows $[i + 1,..m - 1]$. We only need to find the maximum value in these rows.

Why is the above method correct? We can prove it by contradiction.

If $mat[i][j] > mat[i + 1][j]$, suppose there is no peak in the rows $[0,..i]$. Then $mat[i][j]$ is not a peak. Since $mat[i][j]$ is the maximum value of the $i$-th row, and $mat[i][j] > mat[i + 1][j]$, then $mat[i][j] < mat[i - 1][j]$. We continue to consider from the $(i - 1)$-th row upwards, and the maximum value of each row is less than the maximum value of the previous row. When we traverse to $i = 0$, since all elements in the matrix are positive integers, and the values of the cells around the matrix are $-1$. Therefore, at the 0-th row, its maximum value is greater than all its adjacent elements, so the maximum value of the 0-th row is a peak, which contradicts the assumption. Therefore, there must be a peak in the rows $[0,..i]$.

For the case where $mat[i][j] < mat[i + 1][j]$, we can prove in a similar way that there must be a peak in the rows $[i + 1,..m - 1]$.

Therefore, we can use binary search to find the peak.

We perform binary search on the rows of the matrix, initially with the search boundaries $l = 0$, $r = m - 1$. Each time, we find the middle row $mid$ and find the index $j$ of the maximum value of this row. If $mat[mid][j] > mat[mid + 1][j]$, then we search for the peak in the rows $[0,..mid]$, i.e., update $r = mid$. Otherwise, we search for the peak in the rows $[mid + 1,..m - 1]$, i.e., update $l = mid + 1$. When $l = r$, we find the position $[l, j_l]$ of the peak, where $j_l$ is the index of the maximum value of the $l$-th row.

The time complexity is $O(n \times \log m)$, where $m$ and $n$ are the number of rows and columns of the matrix, respectively. The time complexity of binary search is $O(\log m)$, and each time we perform binary search, we need to traverse all elements of the $mid$-th row, with a time complexity of $O(n)$. The space complexity is $O(1)$.

  • class Solution {
        public int[] findPeakGrid(int[][] mat) {
            int l = 0, r = mat.length - 1;
            int n = mat[0].length;
            while (l < r) {
                int mid = (l + r) >> 1;
                int j = maxPos(mat[mid]);
                if (mat[mid][j] > mat[mid + 1][j]) {
                    r = mid;
                } else {
                    l = mid + 1;
                }
            }
            return new int[] {l, maxPos(mat[l])};
        }
    
        private int maxPos(int[] arr) {
            int j = 0;
            for (int i = 1; i < arr.length; ++i) {
                if (arr[j] < arr[i]) {
                    j = i;
                }
            }
            return j;
        }
    }
    
  • class Solution {
    public:
        vector<int> findPeakGrid(vector<vector<int>>& mat) {
            int l = 0, r = mat.size() - 1;
            while (l < r) {
                int mid = (l + r) >> 1;
                int j = distance(mat[mid].begin(), max_element(mat[mid].begin(), mat[mid].end()));
                if (mat[mid][j] > mat[mid + 1][j]) {
                    r = mid;
                } else {
                    l = mid + 1;
                }
            }
            int j = distance(mat[l].begin(), max_element(mat[l].begin(), mat[l].end()));
            return {l, j};
        }
    };
    
  • class Solution:
        def findPeakGrid(self, mat: List[List[int]]) -> List[int]:
            l, r = 0, len(mat) - 1
            while l < r:
                mid = (l + r) >> 1
                j = mat[mid].index(max(mat[mid]))
                if mat[mid][j] > mat[mid + 1][j]:
                    r = mid
                else:
                    l = mid + 1
            return [l, mat[l].index(max(mat[l]))]
    
    
  • func findPeakGrid(mat [][]int) []int {
    	maxPos := func(arr []int) int {
    		j := 0
    		for i := 1; i < len(arr); i++ {
    			if arr[i] > arr[j] {
    				j = i
    			}
    		}
    		return j
    	}
    	l, r := 0, len(mat)-1
    	for l < r {
    		mid := (l + r) >> 1
    		j := maxPos(mat[mid])
    		if mat[mid][j] > mat[mid+1][j] {
    			r = mid
    		} else {
    			l = mid + 1
    		}
    	}
    	return []int{l, maxPos(mat[l])}
    }
    
  • function findPeakGrid(mat: number[][]): number[] {
        let [l, r] = [0, mat.length - 1];
        while (l < r) {
            const mid = (l + r) >> 1;
            const j = mat[mid].indexOf(Math.max(...mat[mid]));
            if (mat[mid][j] > mat[mid + 1][j]) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }
        return [l, mat[l].indexOf(Math.max(...mat[l]))];
    }
    
    
  • impl Solution {
        pub fn find_peak_grid(mat: Vec<Vec<i32>>) -> Vec<i32> {
            let mut l: usize = 0;
            let mut r: usize = mat.len() - 1;
            while l < r {
                let mid: usize = (l + r) >> 1;
                let j: usize = mat[mid]
                    .iter()
                    .position(|&x| x == *mat[mid].iter().max().unwrap())
                    .unwrap();
                if mat[mid][j] > mat[mid + 1][j] {
                    r = mid;
                } else {
                    l = mid + 1;
                }
            }
            let j: usize = mat[l]
                .iter()
                .position(|&x| x == *mat[l].iter().max().unwrap())
                .unwrap();
            vec![l as i32, j as i32]
        }
    }
    
    

All Problems

All Solutions