Reputation: 31
The matrix A is sorted by row and column where A[i][j] < A[i][j+1] and A[i][j] < A[i+1][j]. An additional information is that the first element of each row is smaller than the last element of the previous row, for example :
⎡1 3 5 17⎤
⎢2 4 6 18⎥
⎣7 9 11 20⎦
And I am confused about what role this additional information plays in determining the O(lgn) complexity.
I could come up with O(m) + O(n) as the following:
int search(int mat[4][4], int n, int x)
{
int i = 0, j = n-1; //set indexes for top right element
while ( i < n && j >= 0 )
{
if ( mat[i][j] == x )
{
printf("\n Found at %d, %d", i, j);
return 1;
}
if ( mat[i][j] > x )
j--;
else // if mat[i][j] < x
i++;
}
printf("\n Element not found");
return 0; // if ( i==n || j== -1 )
}
But I do not think I have used the information : the first element of each row is smaller than the last element of the previous row
Could anyone plz give me some hints? Plus this is not homework. Thank you!
Upvotes: 3
Views: 412
Reputation: 3113
What you're currently doing is an exhaustive search (i.e. checking every element once), thus O(n*m). You aren't taking advantage of the sorted nature of the matrix.
Given a sorted list, Binary Search lets you search in O(lg n). Basically, you check the middle element of your list. If it's greater than your target then you know you can ignore the second half of the list. Repeat this process, halfing your search space each time, until you find the element or your search space equals 1 item. In Python code:
import math
def binSearch(value, data):
bottom = 0 #first entry
top = len(data) -1 #last entry
while bottom <= top: #if bottom ever becomes greater than top then the object is not in the list
i = int(bottom + math.floor((top - bottom)/2)) #find the mid-point
if data[i] == value: #we found it
return i
elif data[i] > value:
top = i - 1 #value must be before i
else:
bottom = i + 1 #value must be after i
return None #not found
Now, think about what information you can gather from the matrix structure. You know that given a n x m matrix mat
sorted as you desribed, for any row i
, mat[i][0]
is the lowest items in the row and mat[i][n]
is the highest. Similarly, for any column j, mat[0][j]
is the lowest value fo that column and mat[m][j]
is the highest. That means that if mat[i][0] <= value <= mat[i][n]
is not true then value cannot be in row i. Similarly, if mat[0][j] <= value <= mat[m][j]
is not true then value cannot be in column j.
So the obvious improvement is, for each row that could possibly contain the value, do a binary search.
for row in mat:
if (row[0] <= value) AND (row[len(row) - 1] >= value): #if the value could possibly be in the row
result = binSearch(value, row)
if result: #if we found it
return result
binSearch()
is O(lg m). Worst case scenario is performing binSearch()
on every row, thus O(n * lg m).
I was trying to implement a O(lg n * lg m) solution but I can't figure it out. The problem is that I can only eliminate the top left and bottom right corners of the matrix. I can't eliminate the bottom left or top right.
Upvotes: 1