1 Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: 2 3 Integers in each row are sorted from left to right. 4 The first integer of each row is greater than the last integer of the previous row. 5 For example, 6 7 Consider the following matrix: 8 9 [ 10 [1, 3, 5, 7], 11 [10, 11, 16, 20], 12 [23, 30, 34, 50] 13 ] 14 Given target = 3, return true.
这道题本来思路并不复杂,先对第一列做binary search, 找到target所在的行,再对所在的行做binary search,找到target在或不在。但是我在编程的时候遇到了很多问题,堆栈溢出(StackOverflowError)折腾死我了,一些边界条件的考虑也颇费周折。
我之所以会碰到堆栈溢出的问题是跟我用recursion的方法来做binary search分不开的。众所周知,recursion的一大缺陷就是,浪费空间,容易递归太深造成堆栈的溢出。在这道题中可见一斑。其实它的sample input: [[1][3]], 3 递归的层次并不多,但是我要用recursion就不得不把整个矩阵作为recursion function的参数,结果虽然层次不多但是堆栈依然溢出了。后来想想那不是当然的么,每一层堆栈都要存下整个矩阵,不溢出才怪。所以,我就把方法改成了iteration, 果然就避免了堆栈溢出的问题。由此可见,recursion虽然好想,但是需要很大空间的缺点不容忽视。以后如果我发现有可能递归太深或者每一次递归的参数需要的空间很大,我就应该避免使用递归的方法。
后面我还写了一个程序验证我的想法,我在对找到的行做binary search的时候用递归,不过这一次我用的参数不再是一整个矩阵,而是矩阵的这一行。结果,这次堆栈没有溢出。accept了。这证实了我之前的想法,果然用一个矩阵做递归参数真是太天真了。教训啊,我太naive了。不过,人不是就这样一点一点经验积攒而进步的吗?
第二遍做法:对整个矩阵做binary search:
1 public class Solution { 2 public boolean searchMatrix(int[][] matrix, int target) { 3 // Start typing your Java solution below 4 // DO NOT write main() function 5 if(matrix==null || matrix.length==0 || matrix[0].length==0) 6 return false; 7 int start = 0, end = matrix.length*matrix[0].length-1; 8 9 while(start<=end){ 10 int mid=(start+end)/2, midX=mid/matrix[0].length, 11 midY=mid%matrix[0].length; 12 if(matrix[midX][midY]==target) return true; 13 if(matrix[midX][midY]<target){ 14 start=mid+1; 15 }else{ 16 end=mid-1; 17 } 18 } 19 return false; 20 } 21 }