LeetCode 74. Search a 2D Matrix
原题链接在这里:https://leetcode.com/problems/search-a-2d-matrix/
题目:
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 from left to right.
- The first integer of each row is greater than the last integer of the previous row.
For example,
Consider the following matrix:
[ [1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50] ]
Given target = 3
, return true
.
题解:
可以当成一个一维矩阵来处理,但是本题的难点就是如何将2D矩阵m*n 转换成1D,然后利用二分查找法来解决问题。
转换的重点就在于每个点的位置,在矩阵表示中,我们习惯用(i,j)来表示一个点,这里用所以这就有碍于我们使用(mid/n, mid%n) 来表示。
举例,像题中的例子我可以将其转化为:
position: 0 1 2 3 4 5 6 7 8 9 10 11
values: 1 3 5 7 10 11 16 20 23 30 34 50
row: 0 0 0 0 1 1 1 1 2 2 2 2
column: 0 1 2 3 0 1 2 3 0 1 2 3
其中:行数m=3,列数n=4
如上,这个就是将2D矩阵转化成1行数组的对应表。所以对于二分查找法的初始值为: low=0, high=m*n-1(总共数值的个数,因为从0开始所以减1). 而为了能够方便在given 2D matrix找到需要比对的值,我们还是需要确定行数和列数,通过上表可以看出,行数是position/n, 而列数是position%n, 这样一来,就能很容易的在原矩阵中定位到所需要的值。剩下其他的解题思路,就与二分查找法一模一样了。
Time Complexity: O(log(m*n)), 因为二分法查找的总数是m*n.
Space: O(1).
第二种方法是进行两次二分法查找,第一次找行,第二次找列.
Note: 方法二中,跳出找行的loop后, r 肯定指向开始元素比target小的行, l肯定指向开始元素比target大的行,所以row应该选r.
并且找注意r 有可能为-1. 这是corner case 若是所有元素都比target 大,最后r就会被减到-1. 使用index前一定注意它是否在0到length-1的范围内。
r的初始值要注意-1.
Time Complexity: O(logm + logn) = O(log(m*n)).
Space: O(1).
AC Java:
1 public class Solution { 2 public boolean searchMatrix(int[][] matrix, int target) { 3 /* 4 //Method 1 5 if(matrix == null || matrix.length == 0 || matrix[0].length == 0){ 6 return false; 7 } 8 int m = matrix.length; 9 int n = matrix[0].length; 10 int l = 0; 11 int r = m*n - 1; 12 while(l<=r){ 13 int mid = l + (r-l)/2; 14 if(matrix[mid/n][mid%n] == target){ 15 return true; 16 }else if(matrix[mid/n][mid%n] > target){ 17 r = mid-1; 18 }else{ 19 l = mid+1; 20 } 21 } 22 return false; 23 */ 24 //Method 2 25 if(matrix == null || matrix.length == 0 || matrix[0].length == 0){ 26 return false; 27 } 28 int m = matrix.length; 29 int n = matrix[0].length; 30 int l = 0; 31 int r = m-1; //error 32 while(l<=r){ 33 int mid = l+(r-l)/2; 34 if(matrix[mid][0] == target){ 35 return true; 36 }else if(matrix[mid][0] > target){ 37 r = mid-1; 38 }else{ 39 l = mid+1; 40 } 41 } 42 int row = r; //跳出loop时,r肯定指向开始元素比target小的row, l肯定指向开始i比target大的row 43 //corner case, 如果第一行第一个值逗比target大,那么跳出loop时row是-1. 肯定没有符合target的值 44 if(row < 0){ 45 return false; 46 } 47 l = 0; 48 r = n-1; 49 while(l<=r){ 50 int mid = l+(r-l)/2; 51 if(matrix[row][mid] == target){ 52 return true; 53 }else if(matrix[row][mid] > target){ 54 r = mid-1; 55 }else{ 56 l = mid+1; 57 } 58 } 59 return false; 60 } 61 }