diff --git a/Chapter 10 Sorting and searching/10.9. sorted_matrix_search.md b/Chapter 10 Sorting and searching/10.9. sorted_matrix_search.md index 18c3af3..ed8a22e 100644 --- a/Chapter 10 Sorting and searching/10.9. sorted_matrix_search.md +++ b/Chapter 10 Sorting and searching/10.9. sorted_matrix_search.md @@ -20,16 +20,16 @@ If A[0][3] < num and A[3][0] < num, if A[3][3] < num, return -1. Otherwise it mu If A[0][3] => num or A[3][0] => num, Iterate through the last column, find first row where `A[row][3] > num`. Then iterate that row from the back. If not found, iterate through the last row, do the same. This should take O(N+M) in the worst case. ```python -def search_sorted_matrix(M, N, A, num): +def search_sorted_matrix(A, num): if num < A[0][0] or num > A[M][N]: return 0 if num == A[0][0] or num == A[M][N]: return 1 - if num < A[0][N]: + if num < A[0][N]: # case for small numbers, first row initidx = 0 maxidx = N while True: - i = maxidx // 2 + i = (maxidx + initidx) // 2 if A[0][i] == num: return 1 elif A[0][i] > num: @@ -40,5 +40,222 @@ def search_sorted_matrix(M, N, A, num): if A[0][initidx] < num and A[0][initidx+1] > num: break + # we need to look in column initidx + for i in range(initidx+1, 0, -1): + for j in range(N): + if A[i][j] == num: + return 1 + if A[i][j] > num: + break -``` \ No newline at end of file + elif num < A[M][0]: # case for small numbers, first column + initidx = 0 + maxidx = M + while True: + i = (maxidx + initidx) // 2 + if A[i][0] == num: + return 1 + elif A[i][0] > num: + maxidx = i + elif A[i][0] < num: + initidx = i + + if A[initidx][0] < num and A[initidx+1][0] > num: + break + + # we need to look in column initidx + for i in range(initidx+1, 0, -1): + for j in range(M): + if A[j][i] == num: + return 1 + if A[j][i] > num: + break + + elif num > A[M][0]: + initidx = 0 + maxidx = N + while True: + i = (maxidx + initidx) // 2 + if A[M][i] == num: + return 1 + elif A[M][i] > num: + maxidx = i + elif A[M][i] < num: + initidx = i + + if A[M][initidx] < num and A[M][initidx+1] > num: + initidx += 1 + break + + # we need to look in column initidx + for j in range(initidx, N): + for i in range(M-1, 1, -1): + if A[i][j] == num: + return 1 + if A[i][j] < num: + break + + return 0 +``` + +Complexity is O(logN + ) or O(logM + ), bffI don't know exactly. O(1) space. + +We only want to check rows where num > A[i][0] and num < A[i][M-1]. If it's equal to the top or botton fow, return 1. For example, only rows 1,2 qualify. We check the columns, and maybe 3,4 qualify. Then we only have to check the mini-matrix of the rows and cols. + +> example: + +```python +data = [ + ([ + [0, 1, 3, 5, 6], + [1, 2, 4, 9, 10], + [3, 12, 13, 14, 15], + [6, 17, 18, 25, 26], + [8, 22, 23, 28, 30] + ], 4, 0) + ] +minimatrix = [[0, 1, 3], + [1, 2, 4], + [3, 12, 13]] +``` + +This is recursive, until we either find it or end up with a minimatrix of size 1 and A[i][j] != num, return 0 + +```python +def search_sorted_matrix(A, num): + if num < A[0][0] or num > A[M-1][N-1]: + return 0 + if num == A[0][0] or num == A[M-1][N-1]: + return 1 + + rows = [0, M-1] + cols = [0, N-1] + + while True: + new_rows = [] + new_cols = [] + flag = False + + # check bounded rows + for i in range(rows[0], rows[1]+1): + if A[i][cols[0]] == num or A[i][cols[1]] == num: + return 1 + if A[i][cols[0]] > num: + new_rows.append(i - 1) + flag = False + break + if i == rows[1]: + new_rows.append(i) + flag = False + break + if A[i][cols[0]] < num and A[i][cols[1]] > num: + if not flag: + new_rows.append(i) + flag = True + + # check bounded cols + for j in range(cols[0], cols[1]+1): + if A[rows[0]][j] == num or A[rows[1]][j] == num: + return 1 + if A[rows[0]][j] > num: + new_cols.append(j - 1) + flag = False + break + if j == cols[1]: + new_cols.append(j) + flag = False + break + if A[rows[0]][j] < num and A[rows[1]][j] > num: + if not flag: + new_cols.append(j) + flag = True + + rows = new_rows + cols = new_cols + + return 0 +``` + +The matrix is recursively getting smaller, need to check for false test cases: + +```python +def search_sorted_matrix(A, num): + if num < A[0][0] or num > A[M-1][N-1]: + return 0 + if num == A[0][0] or num == A[M-1][N-1]: + return 1 + + rows = [0, M-1] + cols = [0, N-1] + + while True: + new_rows = [] + new_cols = [] + flag = False + + if rows[0] == rows[1]: + for j in range(cols[0], cols[1]+1): + if A[rows[0]][j] == num: + return 1 + return 0 + + if cols[0] == cols[1]: + for i in range(rows[0], rows[1]+1): + if A[i][cols[0]] == num: + return 1 + return 0 + + # check bounded rows + for i in range(rows[0], rows[1]+1): + if A[i][cols[0]] == num or A[i][cols[1]] == num: + return 1 + if A[i][cols[0]] > num: + new_rows.append(i - 1) + flag = False + break + if i == rows[1]: + new_rows.append(i) + flag = False + break + if A[i][cols[0]] < num and A[i][cols[1]] > num: + if not flag: + new_rows.append(i) + flag = True + + # check bounded cols + for j in range(cols[0], cols[1]+1): + if A[rows[0]][j] == num or A[rows[1]][j] == num: + return 1 + if A[rows[0]][j] > num: + new_cols.append(j - 1) + flag = False + break + if j == cols[1]: + new_cols.append(j) + flag = False + break + if A[rows[0]][j] < num and A[rows[1]][j] > num: + if not flag: + new_cols.append(j) + flag = True + + if len(new_rows) == len(new_cols) == 1 or new_rows[0] == new_rows[1] and new_cols[0] == new_cols[1]: + return 0 + + rows = new_rows + cols = new_cols + + return 0 +``` + +This works for occurring numbers and missing numbers also. + +## Hints and solution + +We can do binary search in each column, but that takes O(Mlog(N)). one binary search per row. + +Keep track of possible rows and cols, where num > first elem, and num < last elem, and keep track of this using arrays, move up, down, left and right around the rows and the columns. + +If we compare `num` to the center number in the matrix, we can eliminate roughly one quarter. hm. + +p410, I don't really understand it. We can discard quarters of the matrix by checking the middle values in the matrix and recursively check the lower left quadrant and the upper right quadrant. \ No newline at end of file diff --git a/Chapter 10 Sorting and searching/10.9. sorted_matrix_search.py b/Chapter 10 Sorting and searching/10.9. sorted_matrix_search.py index e58d49f..237cbcb 100644 --- a/Chapter 10 Sorting and searching/10.9. sorted_matrix_search.py +++ b/Chapter 10 Sorting and searching/10.9. sorted_matrix_search.py @@ -1,38 +1,85 @@ import unittest -M = 5 - 1 -N = 5 - 1 +M = 5 +N = 5 def search_sorted_matrix(A, num): - if num < A[0][0] or num > A[M][N]: + if num < A[0][0] or num > A[M-1][N-1]: return 0 - if num == A[0][0] or num == A[M][N]: + if num == A[0][0] or num == A[M-1][N-1]: return 1 - if num < A[0][N]: - initidx = 0 - maxidx = N - while True: - i = maxidx // 2 - if A[0][i] == num: - return 1 - elif A[0][i] > num: - maxidx = i - elif A[0][i] < num: - initidx = i - if A[0][initidx] < num and A[0][initidx+1] > num: + rows = [0, M-1] + cols = [0, N-1] + + while True: + new_rows = [] + new_cols = [] + flag = False + + if rows[0] == rows[1]: + for j in range(cols[0], cols[1]+1): + if A[rows[0]][j] == num: + return 1 + return 0 + + if cols[0] == cols[1]: + for i in range(rows[0], rows[1]+1): + if A[i][cols[0]] == num: + return 1 + return 0 + + # check bounded rows + for i in range(rows[0], rows[1]+1): + if A[i][cols[0]] == num or A[i][cols[1]] == num: + return 1 + if A[i][cols[0]] > num: + new_rows.append(i - 1) + flag = False break + if i == rows[1]: + new_rows.append(i) + flag = False + break + if A[i][cols[0]] < num and A[i][cols[1]] > num: + if not flag: + new_rows.append(i) + flag = True + + # check bounded cols + for j in range(cols[0], cols[1]+1): + if A[rows[0]][j] == num or A[rows[1]][j] == num: + return 1 + if A[rows[0]][j] > num: + new_cols.append(j - 1) + flag = False + break + if j == cols[1]: + new_cols.append(j) + flag = False + break + if A[rows[0]][j] < num and A[rows[1]][j] > num: + if not flag: + new_cols.append(j) + flag = True + + if len(new_rows) == len(new_cols) == 1 or new_rows[0] == new_rows[1] and new_cols[0] == new_cols[1]: + return 0 + + rows = new_rows + cols = new_cols + return 0 class Test(unittest.TestCase): data = [ ([ [0, 1, 3, 4, 6], - [6, 7, 8, 9, 10], - [11, 12, 13, 14, 15], - [16, 17, 18, 19, 20], - [21, 22, 23, 24, 25] - ], 2, 1) + [1, 3, 4, 7, 14], + [3, 12, 13, 14, 15], + [6, 17, 18, 25, 26], + [8, 22, 23, 28, 30] + ], 2, 0) ] def test_rotate_matrix(self):