给你一个满足下述两条属性的 m x n
整数矩阵:
- 每行中的整数从左到右按非递减顺序排列。
- 每行的第一个整数大于前一行的最后一个整数。
给你一个整数 target
,如果 target
在矩阵中,返回 true
;否则,返回 false
。
示例 1:
**输入:** matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
**输出:** true
示例 2:
![](https://assets.leetcode-cn.com/aliyun-lc-
upload/uploads/2020/11/25/mat2.jpg)
**输入:** matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
**输出:** false
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 100
-104 <= matrix[i][j], target <= 104
方法一:两次二分查找
思路
由于每行的第一个元素大于前一行的最后一个元素,且每行元素是升序的,所以每行的第一个元素大于前一行的第一个元素,因此矩阵第一列的元素是升序的。
我们可以对矩阵的第一列的元素二分查找,找到最后一个不大于目标值的元素,然后在该元素所在行中二分查找目标值是否存在。
代码
[sol1-C++]1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution { public: bool searchMatrix(vector<vector<int>> matrix, int target) { auto row = upper_bound(matrix.begin(), matrix.end(), target, [](const int b, const vector<int> &a) { return b < a[0]; }); if (row == matrix.begin()) { return false; } --row; return binary_search(row->begin(), row->end(), target); } };
|
[sol1-Java]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class Solution { public boolean searchMatrix(int[][] matrix, int target) { int rowIndex = binarySearchFirstColumn(matrix, target); if (rowIndex < 0) { return false; } return binarySearchRow(matrix[rowIndex], target); }
public int binarySearchFirstColumn(int[][] matrix, int target) { int low = -1, high = matrix.length - 1; while (low < high) { int mid = (high - low + 1) / 2 + low; if (matrix[mid][0] <= target) { low = mid; } else { high = mid - 1; } } return low; }
public boolean binarySearchRow(int[] row, int target) { int low = 0, high = row.length - 1; while (low <= high) { int mid = (high - low) / 2 + low; if (row[mid] == target) { return true; } else if (row[mid] > target) { high = mid - 1; } else { low = mid + 1; } } return false; } }
|
[sol1-Golang]1 2 3 4 5 6 7 8
| func searchMatrix(matrix [][]int, target int) bool { row := sort.Search(len(matrix), func(i int) bool { return matrix[i][0] > target }) - 1 if row < 0 { return false } col := sort.SearchInts(matrix[row], target) return col < len(matrix[row]) && matrix[row][col] == target }
|
[sol1-JavaScript]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| var searchMatrix = function(matrix, target) { const rowIndex = binarySearchFirstColumn(matrix, target); if (rowIndex < 0) { return false; } return binarySearchRow(matrix[rowIndex], target); };
const binarySearchFirstColumn = (matrix, target) => { let low = -1, high = matrix.length - 1; while (low < high) { const mid = Math.floor((high - low + 1) / 2) + low; if (matrix[mid][0] <= target) { low = mid; } else { high = mid - 1; } } return low; }
const binarySearchRow = (row, target) => { let low = 0, high = row.length - 1; while (low <= high) { const mid = Math.floor((high - low) / 2) + low; if (row[mid] == target) { return true; } else if (row[mid] > target) { high = mid - 1; } else { low = mid + 1; } } return false; }
|
[sol1-C]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| int binarySearchFirstColumn(int** matrix, int matrixSize, int target) { int low = -1, high = matrixSize - 1; while (low < high) { int mid = (high - low + 1) / 2 + low; if (matrix[mid][0] <= target) { low = mid; } else { high = mid - 1; } } return low; }
bool binarySearchRow(int* row, int rowSize, int target) { int low = 0, high = rowSize - 1; while (low <= high) { int mid = (high - low) / 2 + low; if (row[mid] == target) { return true; } else if (row[mid] > target) { high = mid - 1; } else { low = mid + 1; } } return false; }
bool searchMatrix(int** matrix, int matrixSize, int* matrixColSize, int target) { int rowIndex = binarySearchFirstColumn(matrix, matrixSize, target); if (rowIndex < 0) { return false; } return binarySearchRow(matrix[rowIndex], matrixColSize[rowIndex], target); }
|
复杂度分析
方法二:一次二分查找
思路
若将矩阵每一行拼接在上一行的末尾,则会得到一个升序数组,我们可以在该数组上二分找到目标元素。
代码实现时,可以二分升序数组的下标,将其映射到原矩阵的行和列上。
代码
[sol2-C++]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public: bool searchMatrix(vector<vector<int>>& matrix, int target) { int m = matrix.size(), n = matrix[0].size(); int low = 0, high = m * n - 1; while (low <= high) { int mid = (high - low) / 2 + low; int x = matrix[mid / n][mid % n]; if (x < target) { low = mid + 1; } else if (x > target) { high = mid - 1; } else { return true; } } return false; } };
|
[sol2-Java]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Solution { public boolean searchMatrix(int[][] matrix, int target) { int m = matrix.length, n = matrix[0].length; int low = 0, high = m * n - 1; while (low <= high) { int mid = (high - low) / 2 + low; int x = matrix[mid / n][mid % n]; if (x < target) { low = mid + 1; } else if (x > target) { high = mid - 1; } else { return true; } } return false; } }
|
[sol2-Golang]1 2 3 4 5
| func searchMatrix(matrix [][]int, target int) bool { m, n := len(matrix), len(matrix[0]) i := sort.Search(m*n, func(i int) bool { return matrix[i/n][i%n] >= target }) return i < m*n && matrix[i/n][i%n] == target }
|
[sol2-JavaScript]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var searchMatrix = function(matrix, target) { const m = matrix.length, n = matrix[0].length; let low = 0, high = m * n - 1; while (low <= high) { const mid = Math.floor((high - low) / 2) + low; const x = matrix[Math.floor(mid / n)][mid % n]; if (x < target) { low = mid + 1; } else if (x > target) { high = mid - 1; } else { return true; } } return false; };
|
[sol2-C]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| bool searchMatrix(int** matrix, int matrixSize, int* matrixColSize, int target) { int m = matrixSize, n = matrixColSize[0]; int low = 0, high = m * n - 1; while (low <= high) { int mid = (high - low) / 2 + low; int x = matrix[mid / n][mid % n]; if (x < target) { low = mid + 1; } else if (x > target) { high = mid - 1; } else { return true; } } return false; }
|
复杂度分析
结语
两种方法殊途同归,都利用了二分查找,在二维矩阵上寻找目标值。值得注意的是,若二维数组中的一维数组的元素个数不一,方法二将会失效,而方法一则能正确处理。