240. Search a 2D Matrix II
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:
Integers in each row are sorted in ascending from left to right.
Integers in each column are sorted in ascending from top to bottom.
Example:
Consider the following matrix:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
solution 1: brute force
复杂度 O ( m n ) O(mn) O(mn)
solution 2: binary search
从二维array的左上角向右下角进行search
时间复杂度:
O
(
l
o
g
(
n
!
)
)
O(log(n!))
O(log(n!))
O
(
l
g
(
n
)
+
l
g
(
n
−
1
)
+
l
g
(
n
−
2
)
+
…
+
l
g
(
1
)
)
O(lg(n)+lg(n−1)+lg(n−2)+…+lg(1))
O(lg(n)+lg(n−1)+lg(n−2)+…+lg(1))
=
O
(
l
g
(
n
⋅
(
n
−
1
)
⋅
(
n
−
2
)
⋅
…
⋅
1
)
)
= O(lg(n⋅(n−1)⋅(n−2)⋅…⋅1))
=O(lg(n⋅(n−1)⋅(n−2)⋅…⋅1))
=
O
(
l
g
(
1
⋅
…
⋅
(
n
−
2
)
⋅
(
n
−
1
)
⋅
n
)
)
= O(lg(1⋅…⋅(n−2)⋅(n−1)⋅n))
=O(lg(1⋅…⋅(n−2)⋅(n−1)⋅n))
=
O
(
l
g
(
n
!
)
)
= O(lg(n!))
=O(lg(n!))
class Solution {
private boolean binarySearch(int[][] matrix, int target, int start, boolean vertical) {
int lo = start;
int hi = vertical ? matrix[0].length-1 : matrix.length-1;
while (hi >= lo) {
int mid = (lo + hi)/2;
if (vertical) { // searching a column
if (matrix[start][mid] < target) {
lo = mid + 1;
} else if (matrix[start][mid] > target) {
hi = mid - 1;
} else {
return true;
}
} else { // searching a row
if (matrix[mid][start] < target) {
lo = mid + 1;
} else if (matrix[mid][start] > target) {
hi = mid - 1;
} else {
return true;
}
}
}
return false;
}
public boolean searchMatrix(int[][] matrix, int target) {
// an empty matrix obviously does not contain `target`
if (matrix == null || matrix.length == 0) {
return false;
}
// iterate over matrix diagonals
int shorterDim = Math.min(matrix.length, matrix[0].length);
for (int i = 0; i < shorterDim; i++) {
boolean verticalFound = binarySearch(matrix, target, i, true);
boolean horizontalFound = binarySearch(matrix, target, i, false);
if (verticalFound || horizontalFound) {
return true;
}
}
return false;
}
}
示意图如下
solution 3:
还有一种做法可以在
O
(
m
+
n
)
O(m+n)
O(m+n)的时间解决。
首先预先给定 row 和 col indices,可以是最左下角的点或者最右上角的点。
然后根据这个点与 target 的大小关系来判断如何更新 row 和 col.
-
起始点是右上角的点
1.1 如果 matrix[row][col] > target,由于matrix的特性,target必在当前点的左上位置,又由于起始点在右上角,扫描向左下进行,于是更新时,要使位置向左移,于是 col–
1.2 如果 matrix[row][col] < target,由于matrix的特性,同理, row++
1.3 while循环终止的条件是 col >= 0 && row < matrix.length -
起始点是左下角的点
2.1 如果 matrix[row][col] > target,由于matrix的特性,同理, row–
2.2 如果 matrix[row][col] < target,由于matrix的特性,同理, col++
2.3 while循环终止的条件是 row >= 0 && col < matrix[0].length
public boolean searchMatrix(int[][] matrix, int target) {
// an empty matrix obviously does not contain `target`
if (matrix == null || matrix.length == 0) {
return false;
}
int row = 0;
int col = matrix[0].length - 1;
while (col >= 0 && row < matrix.length) {
if (matrix[row][col] > target) {
col--;
} else if(matrix[row][col] < target) {
row++;
} else {
return true;
}
}
return false;
}
示意图