Description 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.
Example 1:
1 2 3 4 5 6 7 8 Input: matrix = [ [1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50] ] target = 3 Output: true
Example 2:
1 2 3 4 5 6 7 8 Input: matrix = [ [1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50] ] target = 13 Output: false
Difficulty: Medium
Code:
1 2 3 4 5 class Solution { public boolean searchMatrix (int [][] matrix, int target) { } }
题意 在m乘n对矩阵中,检索一个数字是否存在。矩阵中每一行从左到右是从小到大排列的,一行的第一个数字比上一行最后一个数字大。
Solution 1 首先当矩阵为空,或者目标target不在矩阵首尾两个数之间时,直接返回false。
先用二分查找找出target所在的行row,再用二分查找在第row行查找目标target。
当查找所在行时,循环条件为start<end,mid为(start+end+1)/2,mid行第一个元素值为val。退出循环时,start=end,返回start即可。
若val等于target,则返回所在行mid
若val大于target,则end设为mid-1
若val小于target,则start设为mid
当在第row行查找所在列时,循环条件为start<=end,mid为(start+end)/2,row行下标mid元素值为val。退出循环时,表示没有找到,返回null。
若val等于target,则返回所在行mid
若val大于target,则end设为mid-1
若val小于target,则start设为mid+1
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 38 39 40 41 class Solution { public boolean searchMatrix (int [][] matrix, int target) { if (matrix==null || matrix.length==0 || matrix[0 ].length==0 ) return false ; int m = matrix.length, n = matrix[0 ].length; if (matrix[0 ][0 ]>target||matrix[m-1 ][n-1 ]<target) return false ; int row = searchRow(matrix, target, 0 , m-1 ); Integer col = searchCol(matrix, target, row, 0 , n-1 ); if (col==null ) return false ; return true ; } public int searchRow (int [][] matrix, int target, int start, int end) { while (start<end){ int mid = (start+end+1 )/2 ; int val = matrix[mid][0 ]; if (val==target){ return mid; }else if (val>target){ end=mid-1 ; }else { start=mid; } } return start; } public Integer searchCol (int [][] matrix, int target, int row, int start, int end) { while (start<=end){ int mid = (start+end)/2 ; int val = matrix[row][mid]; if (val==target){ return mid; }else if (val>target){ end=mid-1 ; }else { start=mid+1 ; } } return null ; } }
时间复杂度: O(log2 mn)。
空间复杂度: O(1)。
Solution 2 同样在第一列上先用一次二分查找法找到目标值所在的行的位置,然后在该行上再用一次二分查找法来找是否存在目标值。
如果是查找第一个不小于目标值的数,当target在第一列时,会返回target所在的行,但若target不在的话,有可能会返回下一行,不好统一。所以可以查找第一个大于目标值的数,这样只要回退一个,就一定是target所在的行。
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 38 39 40 41 class Solution { public boolean searchMatrix (int [][] matrix, int target) { if (matrix==null || matrix.length==0 || matrix[0 ].length==0 ) return false ; int m = matrix.length, n = matrix[0 ].length; if (matrix[0 ][0 ]>target||matrix[m-1 ][n-1 ]<target) return false ; int row = searchRow(matrix, target, 0 , m-1 ); Integer col = searchCol(matrix, target, row, 0 , n-1 ); if (col==null ) return false ; return true ; } public int searchRow (int [][] matrix, int target, int start, int end) { while (start<end){ int mid = (start+end+1 )/2 ; int val = matrix[mid][0 ]; if (val==target){ return mid; }else if (val>target){ end=mid-1 ; }else { start=mid; } } return start; } public Integer searchCol (int [][] matrix, int target, int row, int start, int end) { while (start<=end){ int mid = (start+end)/2 ; int val = matrix[row][mid]; if (val==target){ return mid; }else if (val>target){ end=mid-1 ; }else { start=mid+1 ; } } return null ; } }
时间复杂度: O(log2 mn)。
空间复杂度: O(1)。
Solution 3 使用双指针也是可以的,初始化时i指向第一行,j指向最后一列。
若matrix[i][j]与target相等直接返回true
若matrix[i][j]小于target则要递增一行i++
若大于target则说明只会在当前行对前部出现,往前移动j–
最后若退出循环也没找到则说明不存在返回false。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution { public boolean searchMatrix (int [][] matrix, int target) { if (matrix==null || matrix.length==0 || matrix[0 ].length==0 ) return false ; int m = matrix.length, n = matrix[0 ].length; int i=0 , j=n-1 ; while (i<m&&j>=0 ){ int cur = matrix[i][j]; if (cur==target) return true ; if (cur>target){ j--; }else { i++; } } return false ; } }
时间复杂度: O(m+n)。
空间复杂度: O(1)。
Solution 4 直接将整个矩阵当作有序数组,最左侧是右下角元素下标为0,最右侧是右下角元素下标为m*n-1。
mid设为(left+right)/2,其在矩阵中对位置为matrix[mid/n][mid%n],然后据此进行二分查找。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public boolean searchMatrix (int [][] matrix, int target) { if (matrix==null || matrix.length==0 || matrix[0 ].length==0 ) return false ; int m = matrix.length, n = matrix[0 ].length; int left = 0 , right = m*n-1 ; while (left<=right){ int mid=(left+right)/2 ; int val = matrix[mid/n][mid%n]; if (val==target){ return true ; }else if (val>target){ right=mid-1 ; }else { left=mid+1 ; } } return false ; } }
时间复杂度: O(log2 mn)。
空间复杂度: O(1)。