Matrix · 2 of 10
Search an element in a matrix
Find a number in a grid that grows to the right and grows downward, by starting at the top right corner and walking down a staircase.
- Simple way
- time O(m*n)
room O(1) - Clever way
- time O(m + n)
room O(1)
The problem, simply
You get a grid of numbers, a matrix with m rows and n columns. Every row goes up from left to right. Every column goes up from top to bottom. You also get one number, the target.
Say true if the target is somewhere in the grid, and false if it is not.
There is a stricter version of this grid too, where each row starts after the row above it ends, like the pages of a book. It has its own trick, shown in Way 3.
A story to remember it
Picture it
Each row grows from left to right, and each column grows from top to bottom. The top right corner, 11, is the biggest of its row and the smallest of its column.
- looking now
Examples
Target in the middle
- In
matrix = [[1,4,7,11],[2,5,8,12],[3,6,9,16],[7,10,13,17]], target = 10- Out
true
The staircase walk goes 11, 7, 8, 9, 13, 10 and finds it at row 3, column 1.
Target not there
- In
same matrix, target = 15- Out
false
The walk goes 11, 12, 16, 9, 13 and then falls off the bottom of the grid. 15 would have to be between 13 and 16, and it is not.
Target in a corner
- In
same matrix, target = 1- Out
true
The walk moves left across row 0 (11, 7, 4) and finds 1. The smallest number is always at the top left.
Smaller than everything
- In
same matrix, target = 0- Out
false
Every number in row 0 is too big, so the walk steps left past column 0 and stops.
Empty grid
- In
matrix = [], target = 5- Out
false
Nothing to search. Return false before touching matrix[0].
Way 1: the simple way
Look at every box on the wall, one by one, until you find the target or run out of boxes.
- For each row
r, and each columncin that row: - If
matrix[r][c] == target, saytrue. - If the loops end, say
false.
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
for (int[] row : matrix) {
for (int value : row) {
if (value == target) return true; // looked at every box until a match
}
}
return false;
}
}How long it takes: in the worst case we look at every cell, O(m*n). Extra room: nothing, O(1). It ignores the sorted order completely. A better first step is a binary search in each row, O(m log n), but there is a way that uses both directions at once.
Way 2: the clever way
Stand at the top right corner. From there, moving left always makes the number smaller, and moving down always makes it bigger. So every comparison tells you which way to go.
- Start at
row = 0,col = n - 1. - If the number equals the target, say
true. - If it is bigger than the target, the whole column below is bigger too. Move left:
col--. - If it is smaller than the target, the whole row to the left is smaller too. Move down:
row++. - If you walk off the grid, say
false.
The grey cells in the animation are the boxes we never had to open.
Staircase search for 10 from the top right corner
01 / 07
Start at the top right corner, row 0 and column 3. The number here is 11. Everything to its left is smaller, everything below it is bigger.
- target
- 10
- row
- 0
- col
- 3
- here
- 11
- looking now
- seen
- answer
- ignored
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
if (matrix.length == 0 || matrix[0].length == 0) return false;
int m = matrix.length, n = matrix[0].length;
int row = 0, col = n - 1; // top right corner
while (row < m && col >= 0) {
int here = matrix[row][col];
if (here == target) return true;
if (here > target) col--; // this column is all too big below here
else row++; // this row is all too small left of here
}
return false; // walked off the grid
}
}How long it takes: each step removes one row or one column, and there are only m + n of those, so O(m + n). Extra room: two whole numbers, O(1).
The bottom left corner works too, with the moves flipped: too big means go up, too small means go right. The top left and bottom right corners do not work, because from there both moves go the same way and a comparison cannot pick one.
Way 3: when rows follow each other
Some interviewers mean a stricter grid: each row is sorted, and the first number of a row is bigger than the last number of the row above. Then the whole grid, read row after row, is one long sorted line. You can binary search that line without building it. Seat i of the line lives at matrix[i / n][i % n].
Binary search on a grid that reads like one sorted line
01 / 04
Read the grid like one long line of 12 seats, numbered 0 to 11. Seat number i lives at row i / 4 and column i % 4. The whole line is still possible.
- target
- 16
- lo
- 0
- hi
- 11
- looking now
- answer
- path
- ignored
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
if (matrix.length == 0 || matrix[0].length == 0) return false;
int m = matrix.length, n = matrix[0].length;
int lo = 0, hi = m * n - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
int here = matrix[mid / n][mid % n]; // seat number to row and column
if (here == target) return true;
if (here < target) lo = mid + 1;
else hi = mid - 1;
}
return false;
}
}This takes O(log(m*n)) time and O(1) room. It does not work on the grid from Way 2, where a row can start smaller than the row above ends (look at 7 in row 3 of the first example).
Watch out for
- An empty matrix or an empty first row. Check before reading
matrix[0].length. - The loop must check both
row < mandcol >= 0before reading a cell. - Using the Way 3 binary search on a grid that is only sorted by rows and columns. It gives wrong answers.
- In Way 3,
m * ncan overflow anintfor huge grids. Uselongfor the indexes then.
What interviewers ask next
- Return where the target is, not only
true. Returnnew int[]{row, col}at the match and{-1, -1}at the end. - Count how many numbers are less than or equal to
x. Start at the bottom left. If the number is at mostx, the whole column above it counts, so addrow + 1and move right; otherwise move up. This isO(m + n)and is the heart of the Kth smallest problem. - Can you beat
O(m + n)on a row and column sorted grid? Not in general. The cells on the diagonal from bottom left to top right can be in any order relative to each other, so you may need to check all of them. - What if the grid is huge and wide, like
mmuch smaller thann? Binary search each row,O(m log n), which beatsO(m + n)whenmis tiny.
Remember this
Grown-up words: the shoe wall is a row and column sorted matrix, the staircase walk is called staircase search or search space reduction, and reading the stricter grid as one long line is binary search over a flattened index.