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.
For example:
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.
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.
How would you efficiently find a peak element in the given 2D matrix?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach involves checking every single element in the grid to see if it's a peak. We compare each element with all of its neighbors to determine if it's greater than or equal to them.
Here's how the algorithm would work step-by-step:
def find_peak_element_ii_brute_force(matrix):
number_of_rows = len(matrix)
number_of_columns = len(matrix[0])
for row_index in range(number_of_rows):
for column_index in range(number_of_columns):
current_element = matrix[row_index][column_index]
# Check neighbors: up, down, left, right
up = matrix[row_index - 1][column_index] if row_index > 0 else -1
down = matrix[row_index + 1][column_index] if row_index < number_of_rows - 1 else -1
left = matrix[row_index][column_index - 1] if column_index > 0 else -1
right = matrix[row_index][column_index + 1] if column_index < number_of_columns - 1 else -1
# Need to handle edge cases where neighbors don't exist
is_peak = True
if up != -1 and current_element < up:
is_peak = False
if down != -1 and current_element < down:
is_peak = False
if left != -1 and current_element < left:
is_peak = False
if right != -1 and current_element < right:
is_peak = False
# If it's a peak, return its coordinates
if is_peak:
return [row_index, column_index]
return []
The core idea is to repeatedly narrow down the search area until we find a peak. We accomplish this by focusing on rows and columns with the greatest potential to contain a peak element.
Here's how the algorithm would work step-by-step:
def find_peak_grid(matrix):
row_count = len(matrix)
column_count = len(matrix[0])
left_boundary = 0
right_boundary = column_count - 1
while left_boundary <= right_boundary:
middle_column = (left_boundary + right_boundary) // 2
#Find the row index with the largest element in the middle column
max_row_index = 0
for row_index in range(1, row_count):
if matrix[row_index][middle_column] > matrix[max_row_index][middle_column]:
max_row_index = row_index
#Check if the largest element is a peak
is_left_bigger = middle_column > 0 and matrix[max_row_index][middle_column - 1] > matrix[max_row_index][middle_column]
is_right_bigger = middle_column < column_count - 1 and matrix[max_row_index][middle_column + 1] > matrix[max_row_index][middle_column]
# If the current element is a peak, return the location
if not is_left_bigger and not is_right_bigger:
return [max_row_index, middle_column]
#Eliminate half of the matrix where the peak cannot exist
if is_left_bigger:
right_boundary = middle_column - 1
#Eliminate half of the matrix where the peak cannot exist
else:
left_boundary = middle_column + 1
return None
Case | How to Handle |
---|---|
Null or empty matrix | Return null or throw an IllegalArgumentException, as a peak cannot exist in an empty matrix. |
Matrix with only one row or one column | Iterate through the single row or column to find the maximum element, which is the peak. |
Matrix with only one element | Return the coordinates of that single element as the peak. |
All elements in the matrix are the same | Any element can be considered a peak, so return the coordinates of the first element. |
Large matrix (performance considerations) | Binary search approach on rows or columns ensures logarithmic time complexity for large matrices. |
Matrix with negative numbers | The algorithm compares values, so negative numbers do not affect the correctness of the peak finding logic. |
Multiple peak elements exist | The algorithm is designed to find and return any one valid peak element, not necessarily all of them. |
Integer overflow when comparing values | Using the correct comparison operators avoids potential integer overflow issues. |